假设我们通过构造一个新的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都会重置那个状态。