如何在ESM模块中使用vm.runInThisContext运行CommonJS代码?
解决方案
方法1:手动注入require到VM上下文
在ESM环境中,全局作用域没有内置require,但可以通过node:module模块的createRequire方法生成符合CommonJS规范的require函数,再将它注入到VM执行的上下文中。
示例代码:
import vm from "node:vm"; import { createRequire } from "node:module"; // 创建当前ESM模块对应的require函数 const require = createRequire(import.meta.url); // 定义待执行的CommonJS代码 const code = ` const path = require("path"); console.log(path.resolve("test.mjs")); `; // 创建VM上下文并注入require const context = vm.createContext({ require }); // 编译代码并在指定上下文执行 const script = new vm.Script(code); script.runInContext(context);
方法2:使用runInNewContext直接传入上下文
简化写法,直接通过vm.runInNewContext将包含require的上下文传入:
import vm from "node:vm"; import { createRequire } from "node:module"; const require = createRequire(import.meta.url); const code = ` require("path").resolve("test.mjs"); `; // 直接传入包含require的上下文对象 vm.runInNewContext(code, { require });
方法3:模拟完整CommonJS模块环境
如果待执行代码依赖module、exports、__dirname等CommonJS变量,可以注入这些变量以实现更完整的兼容:
import vm from "node:vm"; import { createRequire } from "node:module"; import { fileURLToPath } from "node:url"; import { dirname } from "node:path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const require = createRequire(import.meta.url); const module = { exports: {} }; const exports = module.exports; const context = vm.createContext({ require, module, exports, __filename, __dirname }); const code = ` const path = require("path"); module.exports.resolvedPath = path.resolve(__dirname, "test.mjs"); `; const script = new vm.Script(code); script.runInContext(context); // 获取执行后导出的内容 console.log(context.module.exports.resolvedPath);
关键说明
createRequire(import.meta.url)生成的require会以当前ESM模块的路径为基准解析模块,和CommonJS环境下的require行为一致。- VM执行的代码默认与当前模块作用域隔离,必须显式注入需要的变量才能在代码中使用。
内容的提问来源于stack exchange,提问作者jantimon
相关产品推荐
相关产品推荐

