Given a package that exposes async/dynamic exports. Which I currently import this way (but I could import it differently):
(async function() {
const libEd = await import("../../.cache/ed25519wars/index.js");
})();
I intend to re-expose some functions from libEd as part of a class:
export class Something {
static from_X() {
return libEd.genFromX();
}
do_Y() {
return libEd.doY();
}
}
How can I do this ?
For more info:
The package that exposes async/dynamic exports is generated by webpack packing webassembly. I'm not sure if I can change anything about this part
I could definitely change the way I import that package
I could also change the way I re-expose / group the functions (and use something else than a class)
There's a couple of ways I would approach this:
If the class doesn't need to be instantiated immediately, then I would await the library loading, then pass it to the class constructor. This is the cleanest way as the library is always defined within the class.
If the class must be instantiated before fetching the library, then methods in the class must handle the situation when it is not defined (e.g. not loaded yet). You can then call something like await myClassInstance.init() to fetch the library. I typically provide a fallback for each method if the library is not loaded yet, perhaps it returns an empty string or a dummy UI.
EDIT: adding TypeScript example for option 1
interface MyLibrary {
libraryMethod: () => void;
}
class ExampleClass {
localLib: MyLibrary;
constructor(lib: MyLibrary) {
this.localLib = lib;
}
myClassMethod() {
this.localLib.libraryMethod();
}
}
async function run() {
// first we fetch the remote library
const myLibrary: MyLibrary | undefined = await import('/lib.js');
// good practise to add some check here
if (!myLibrary) {
throw Error('failed to fetch myLib');
}
// then we create the class instance using the downloaded library
const myClassInstance = new ExampleClass(myLibrary);
// now we can call our class method which definitely has the remote library
myClassInstance.myClassMethod();
}
I ended up settling on either of three methods:
#Tim's method (accepted answer): include the import in the class properties, and await at constructor time.
But: there might be overhead associated with storing the import in each instance.
awaiting in each method of the class to have the import defined there:
export class Something {
static async from_X() {
const libEd = await loadLibProm();
return libEd.genFromX();
}
async do_Y() {
const libEd = await loadLibProm();
return libEd.doY();
}
}
But: the class API is now all async and more awkward to use.
Pre-loading the import at code start. And hoping the load is going to be finished when the class is called.
let libEd: typeof import("../../.cache/ed25519wars/index.js");
async function loadLibProm(): Promise<
typeof import("../../.cache/ed25519wars/index.js")
> {
libEd = await import("../../.cache/ed25519wars/index.js");
return libEd;
}
loadLibProm(); // this somehow starts running the promise ?? wut ? Anyways that's what we want
export class Something {
static from_X() {
return libEd.genFromX();
}
do_Y() {
return libEd.doY();
}
}
But: this needs better error handling for the case an instance of the class is created before the import is finished / after the import failed.
Related
I stumbled across this question but I don't think I want to use an alias
I want to extend the express anyFilesInterceptor so I can work with a custom file object. I am not sure how to extend a decorator in NestJS.
So as a work around I tried decorator composition from another question. However, I am getting an error just trying to create a very basic (example in documentation) decorator
import { applyDecorators, createParamDecorator, ExecutionContext } from "#nestjs/common";
import { AnyFilesInterceptor } from "#nestjs/platform-express";
export function Test() {
return applyDecorators(
AnyFilesInterceptor,
TestDecorator
)
}
export const TestDecorator = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
Now I can see from other discussions and the function naming that AnyFilesInterceptor is a mixin that returns a class while TestDecorator created by createParamDecorator likely only works on parameters.
Does NestJS have a way to create a class decorator? Or to extend existing decorators?
actually the AnyFilesInterceptor is a function itself that produces an interceptor (which is any class that implements NestInterceptor).
You can see it by the usage: while 'other' interceptors may be used by simply giving the class to the UseInterceptor() decorator, this interceptor needs invocation (without new keyword).
Example:
#UseInterceptor(RegularInterceptor)
//or
#UseInterceptor(new RegularInterceptor())
// AnyFilesInterceptor is a function returning a class
#UseInterceptor(AnyFilesInterceptor())
//or
#UseInterceptor(new (AnyFilesInterceptor())({/* some multer options here */))
so basically if you want to extend the AnyFilesInterceptor you simply need to define a class inteceptor of your own:
export class MyAllFilesInterceptor extends AnyFilesInterceptor() {
// YOU MUST OVERRIDE THE `intercept` METHOD!
// also, give options to the `AnyFilesInterceptor` method if you wish
}
What is the correct way (or a better way) to access emit in the separated logic file?
This is what I did currently that works:
foo.js
export default (emit) => {
const foo = () => { emit('bar') };
return { foo };
}
Then on the consuming component:
import { defineComponent } from '#vue/composition-api';
import foo from './foo';
export default defineComponent({
setup(props, { emit }) {
const { foo } = foo(emit);
return { foo };
}
});
But I wonder if there is a more appropriate way on doing this? Or is it a bad practice to call emit inside a consumable file?
You probably have found the solution, but in case you would try similar way (as originally asked in question), there's this option called getCurrentInstance that has an emitter (the Vue 2 plugin for Composition API has one too).
import { getCurrentInstance } from 'vue';
export default () => {
const { emit } = getCurrentInstance();
const foo = () => {
emit('bar');
};
return { foo };
}
But bear in mind that this will only work for calling functions/components that have the SetupContext.
Edit
The above solution will work for Vue 3, yet with earlier version of Vue + the Composition API plugin, there is but a slight difference: As with the rest of the Instance Properties, you'll have to prefix it with $ to become $emit. (The following example now assumes Typescript as the target language, as mentioned on the comment).
import { getCurrentInstance } from '#vue/composition-api';
export default () => {
// Ugly workaround, since the plugin did not have the `ComponentInstance` type exported.
// You could use `any` here, but that would defeat the purpose of having type-safety, won't it?
// And we're marking it as `NonNullable` as the consuming components
// will most likely be (unless desired otherwise).
const { $emit, ...context } = getCurrentInstance() as NonNullable<ReturnType<typeof getCurrentInstance>>;
const foo = () => {
$emit.call(context, 'bar');
};
return { foo };
}
For Vue 3's Composition API, however, they do have this ComponentInternalInstance interface exported.
P.S. It's probably best to stick to the old-school way of assigning the instance to a variable and do context.$emit or vm.$emit rather than having to explicitly specify a context for everything. I initially came up with this idea without realizing that those Instance Properties are probably meant for internal uses, which is not exactly the case with the next Composition API.
This question pertains to testing javascript and mocking functions.
Say I have a module that looks like this:
export function alpha(n) {
return `${n}${beta(n)}${n}`;
}
export function beta(n) {
return new Array(n).fill(0).map(() => ".").join("");
}
Then I can't test it the following way:
import * as indexModule from "./index";
//Not what we want to do, because we want to mock the functionality of beta
describe("alpha, large test", () => {
it("alpha(1) returns '1.1'", () => {
expect(indexModule.alpha(1)).toEqual("1.1"); //PASS
});
it("alpha(3) returns '3...3'", () => {
expect(indexModule.alpha(3)).toEqual("3...3"); //PASS
});
});
//Simple atomic test
describe("beta", () => {
it("beta(3) returns '...'", () => {
expect(indexModule.beta(3)).toEqual("..."); //FAIL: received: 'x'
});
});
//Here we are trying to mutate the beta function to mock its functionality
describe("alpha", () => {
indexModule.beta = (n) => "x";
it("works", () => {
expect(indexModule.alpha(3)).toEqual("3x3"); //FAIL, recieved: '3...3'
});
});
However, if split the module into two:
alpha.js
import { beta } from "./beta";
export function alpha(n) {
return `${n}${beta(n)}${n}`;
}
beta.js
export function beta(n) {
return new Array(n).fill(0).map(() => ".").join("");
}
Then I can mutate the beta module, and alpha knows about it:
import { alpha } from "./alpha";
import * as betaModule from "./beta";
describe("alpha", () => {
betaModule.beta = (n) => "x";
it("works", () => {
expect(alpha(3)).toEqual("3x3"); //PASS
});
});
Why is this the case? I'm looking for a technically specific answer.
I have a Github branch with this code here, see the mutateModule and singleFunctionPerModuleAndMutate folders.
As an additional question - in this example I am mutating the module by directly reassigning properties. Am I right in understanding that using jest mock functionality is going to be essentially doing the same thing?
ie. If the reason that the first example doesn't work but the second doesn't is due to the mutation, then it necceserily means that using the jest module mocking functions is similarly not going to work.
As far as I know - there is not way to mock a single function in a module, while testing that module, as this jest github issues talks about. What I'm wanting to know - is why this is.
Why does mutating a module update the reference if calling that module from another module, but not if calling from itself?
"In ES6, imports are live read-only views on exported values".
When you import an ES6 module you essentially get a live view of what is exported by that module.
The live view can be mutated, and any code that imports a live view of the module exports will see the mutation.
That is why your test works when alpha and beta are in two different modules. The test modifies the live view of the beta module, and since the alpha module uses the live view of the beta module, it automatically uses the mocked function instead of the original.
On the other hand, in the code above alpha and beta are in the same module and alpha calls beta directly. alpha does not use the live view of the module so when the test modifies the live view of the module it has no effect.
As an additional question - in this example I am mutating the module by directly reassigning properties. Am I right in understanding that using jest mock functionality is going to be essentially doing the same thing?
There are a few ways to mock things using Jest.
One of the ways is using jest.spyOn which accepts an object and a method name and replaces the method on the object with a spy that calls the original method.
A common way to use jest.spyOn is to pass it the live view of an ES6 module as the object which mutates the live view of the module.
So yes, mocking by passing the live view of an ES6 module to something like jest.spyOn (or spyOn from Jasmine, or sinon.spy from Sinon, etc.) mutates the live view of the module in essentially the same way as directly mutating the live view of the module like you are doing in the code above.
As far as I know - there is not way to mock a single function in a module, while testing that module, as this jest github issues talks about. What I'm wanting to know - is why this is.
Actually, it is possible.
"ES6 modules support cyclic dependencies automatically" which means that the live view of a module can be imported into the module itself.
As long as alpha calls beta using the live view of the module that beta is defined in, then beta can be mocked during the test. This works even if they are defined in the same module:
import * as indexModule from './index' // import the live view of the module
export function alpha(n) {
return `${n}${indexModule.beta(n)}${n}`; // call beta using the live view of the module
}
export function beta(n) {
return new Array(n).fill(0).map(() => ".").join("");
}
What I find interesting is that none of your code would work in a browser.
Module ("./some/path/to/file.js"):
const x = () => "x"
const y = () => "y"
export { x, y }
You cannot modify a named import as they are constants:
import { x } from "./some/path/to/file.js"
x = () => {} //Assignment to constant variable.
You also cannot assign to a readonly property of a namespace import.
import * as stuff from "./some/path/to/file.js"
stuff.y = () => {} //Cannot assign to read only property 'y' of...
Here's a codepen which also shows why indexModule.alpha !== alpha from the module: https://codepen.io/bluewater86/pen/QYwMPa
You are using the module to encapsulate your two functions but for the reasons above, this is a bad idea. You really need to encapsulate those functions in a class so that you can mock them appropriately.
//alphaBeta.js
export const beta = n => new Array(n).fill(0).map(() => ".").join("");
export default class alphaBeta {
static get beta() { return beta }
beta(n) {
beta(n)
}
alpha(n) {
return `${n}${this.beta(n)}${n}`;
}
}
export { alphaBeta }
And finally by moving to default/named imports instead of namespace imports you will have no need to use the cyclic dependency hack. Using default/named imports means that you will be importing the same in-memory view of the exports that the module exported. i.e. importer.beta === exporter.beta
import alphaBetaDefault, { alphaBeta, beta } from "./alphaBeta.js"
alphaBeta.prototype.beta = (n) => "x";
describe("alphaBeta", () => {
it("Imported function === exported function", () => {
expect(alphaBeta.beta).toEqual(beta); //PASS
});
const alphaBetaObject = new alphaBeta
it("Has been mocked", () => {
expect(alphaBetaObject.alpha(3)).toEqual("3x3");
});
alphaBeta.prototype.beta = (n) => "z";
it("Is still connected to its prototype", () => {
expect(alphaBetaObject.alpha(3)).toEqual("3z3");
});
const secondObject = new alphaBetaDefault
it("Will still be mocked for all imports of that module", () => {
expect(secondObject.alpha(3)).toEqual("3z3");
});
});
Note : Its not for global variable but for a global common function to perform a functionality on all components
I am working on an angular app where I have around 400 components in different modules, almost all components have one same kind of functionality as mentioned below
There is a sections on many pages which shows a "How to work section" which can be closed by users and will remain closed unless they open it again, I have done it with cookies which I set on click on close or open icon but this function is written in a component and this needs to be imported in other components
I want to create a functions somewhere which perform this functionality on click on icon and can be called without importing any component in others.
One way to do it ( as I thought ) could be create a JavaScript function in a file and load it in index file and then call this function on click on close and open icon
Not sure if this is the best way to do this. Hope someone will come up with a better solution.
1. create your global function service, i.e. 'funcs.services.ts' under 'services' directory:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class FuncsService {
constructor() { }
myGlobalAddFunction(a){
return a++;
}
mySecondFunc(){
// add more... and so on
}
}
2. Import the function in your component:
// your path may different
import { FuncsService } from './../services/funcs/funcs.service';
//...
constructor(
private funcs: FuncsService
) {}
ngOnInit(): void {
let x = 1;
myResult = this.funcs.myGlobalAddFunction(x);
// Then you are expecting 2 for return value
}
3. Hope that works... :)
You can export a function that is a written in .ts file and then call it in all your components.
export function myFunction(){
// Do something
}
And then import the function myFunction() in other components. That works fine for me and can be useful in certain cases
This isn't the best solution (in my opinion). The best solution would be to either create a service, or an utils class.
But if you want to do this, I suggest you make a JS file, that you declare in your angular-cli.json file under the scripts property, containing your functions.
EDIT Now that you've came back to reason, here is a code sample to make utils classes.
export const IMG_UTILS = {
convertPngToJpg = (picture: any) => {
// Your logic here
}
};
export const VIEW_MANAGER = {
isAdblockActive = () => {
// test if an ad-blocker is active
}
};
You can make any utils class you want in a const, then put it into a file. Then, you can put this file in an utils folder, and request it with
import { VIEW_MANAGER } from 'src/app/utils/view-manager';
Otherwise, you can make a service, which is handled by Angular, with a console command such as
ng g s services/view-manager/view-manager
And it will behave the exact same way : you will import it in your components to use it.
Hope this helps !
The most recommended way is to use a service and inject it whenever needed, but there is a way to have a function available globally.
Although I don't think it's a really good idea, you can add the function in the index.html file, then whenever you want to use it, you have to use #ts-ignore to avoid an error from being thrown.
e.g
index.html
<script>
function globalFunc(){
alert(2)
}
</script>
anywhere else on the app
// #ts-ignore
globalFunc();
List item
Just to chime in with possibly a duplicate answer albeit more fleshed out... I have a utilities class which I use.
For example:
export class Utilities {
// Simple promise wrapper for setTimeout. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#creating_a_promise_around_an_old_callback_api
public static Wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
}
The class is referenced in a component via the import statement:
import { Utilities } from 'path/to/Utilities';
And then you can call your static methods thus:
Utilities.Wait(30000)
.then(() => DoStuff())
.catch(() => console.log('Darn!'));
I would tend to use RxJs but I've written it this way to keep things a little cleaner.
I'm trying to override specific function in a library.
In my case, I'm trying to override some functions on Framework7. The library simply has class called Framework7, in non ES6 javascript, creating instance of application would look like this:
var app = new Framework7();
so I assume it's extendable, so here my code to extends it:
export class Application extends Framework7 {
constructor(options) {
super(options);
}
}
the code run fine, however, when I try to override one of the function, let say showPreloader, the function itself is never called
export class Application extends Framework7 {
constructor(options) {
super(options);
}
showPreloader(title) {
console.log('this not printed :(');
super(title); // this is not called as well
// but showPreloader() from Framework7 still called
}
}
I also try different approach to override it, i come with a solution like this:
export class Application extends Framework7 {
constructor(options) {
super(options);
this.showPreloader = (title) => {
console.log('print me!'); // printed! :D
super(); // oh, wait! cannot call super from here! :(
}
}
}
However, it looks a bit ugly and I cannot call super from there.
Is there any workaround so I can override a function from library and calling the base function via super (or anything?)
I assume it's extendable
Don't. Read the docs, ask the authors, or read the source yourself.
In your case, the library you've chosen doesn't exactly follow best practises, it just installs its methods directly on the app "instance". It's a factory function, not a constructor.
Is there any workaround so I can override a function from library and calling the base function?
Yes, by storing the original method in a variable before overwriting it. You then can call it using .call(this) (like inheritance was done in ES5).
…
const original = this.showPreloader;
this.showPreloader = (title) => {
console.log('print me!'); // printed! :D
original.call(this, title);
}
However, that's no fun, especially since it's not just a few instance-specific methods but actually all of them. So you'd better drop ES6 class syntax and "subclassing" here, and use a parasitical inheritance approach instead:
function MyFramework7(options) {
const app = new Framework7(options);
const {showPreloader, …} = app; // all the original methods
… // mess with the object to your liking
return app;
}
Or maybe you don't even need to wrap it in a function, as app is a singleton I guess.