I've found here that imported modules are accepted as SyntheticModule()-s when linking a SourceTextModule(), but i've managed to get it work as SourceTextModule()-s as well, like the documentation describes: https://nodejs.org/api/vm.html#class-vmmodule .
Either way, i need to normally import
the module to make its values available from context. This is a bit defeating the purpose of constructing a module based only on text, especially when it comes to a source text importing itself: the linker will only ever find the unlinked version. How do I create an acceptable version of a vm.Module itself to the linker?
export async function modularise(resource, identifier, home, globals = {}) {
// uses --experimental-vm-modules
let {SourceTextModule,createContext,SyntheticModule} = await import("vm");
let {default: {resolve}} = await import("path");
let module = new SourceTextModule(resource || "", {
identifier,
context: createContext({imports: new Map(),...globals}),
initializeImportMeta: meta => Object.assign(meta, {url: resolve(identifier)}),
importModuleDynamically: identifier => import(identifier)
});
// saving reference to unlinked self
module.context.imports[identifier] = module;
await module.link((identifier, {context}) => context.imports.has(
identifier = /^\./.test(identifier) ? resolve(identifier) : identifier
)
// the self-referential import will always remain unlinked
? context.imports.get(identifier)
: import(identifier).then(module =>
context.imports.set(identifier, module) &&
new SourceTextModule(Object.getOwnPropertyNames(module)
.sort(name => name != "default" || -1)
.map((name, index, exports) => name == "default"
? "export default imports.get(\"" + identifier + "\").default;"
: "export const {" + exports.splice(index).join(",") + `}=
imports.get("` + identifier + "\");")
.join("\n"), {identifier, context}
)
)
);
// statement never reached.
await module.evaluate();
return module;
};