如何链接由vm创建的模块的导入依赖项.SourceTextModule到它?



假设我们通过构造一个新的vm.SourceTextModule对象来创建一个名为app的模块:

const context = {
exports: {},
console,  // custom console object
};
const sandbox = vm.createContext(context);
const app = new vm.SourceTextModule(
`import path from 'path';
console.log(path.resolve('./src'));`,
{
context: sandbox,
}
);

根据Node.js文档,要从path模块获取默认的export,我们应该"link"app模块导入的依赖项。
要实现这一点,我们应该将linker回调传递给app.link方法:

async function linker(specifier, referencingModule) {
// the desired logic...
}
await app.link(linker);

如何正确实现linker功能,以便我们可以在新建的app模块中导入path模块并使用它:

await app.evaluate();  // => /home/user/Documents/project/src

注:我们正在使用TypeScript,所以我检查了我们是否已经安装了path包的类型。

package.json:

"@types/node": "^17.0.31",

我发现https://github.com/nodejs/node/issues/35848有人贴了一个代码片段。

从那里我改编了以下链接器回调:

const imports = new Map();
async function linker(specifier, referencingModule) {
if (imports.has(specifier))
return imports.get(specifier);

const mod = await import(specifier);
const exportNames = Object.keys(mod);
const imported = new vm.SyntheticModule(
exportNames,
() => {
// somehow called with this === undefined?
exportNames.forEach(key => imported.setExport(key, mod[key]));
},
{ identifier: specifier, context: referencingModule.context }
);
imports.set(specifier, imported);
return imported;
}

来自GitHub问题的代码片段在Node 18.7.0上对我不起作用,因为传递给SyntheticModule构造函数的评估器回调以某种方式被this设置为undefined调用。这可能是一个Node错误。

我还在Map中缓存了导入的SyntheticModules,因为如果它们有内部状态,每次创建一个新的SyntheticModule都会重置那个状态。