NodeJS:能否向isolated-vm的Isolate传递第三方模块?
问题描述
我尝试在isolated-vm的Isolate中执行脚本代码,该脚本需要lodash、node-xlsx等第三方包作为依赖。请问能否将这些依赖模块传递给Isolate?
尝试传递模块时出现以下错误:
TypeError: [object Module] could not be cloned.
代码示例:
import ivm from 'isolated-vm' import _ from 'lodash-es' (async function() { try{ let code = ` async function setup() { log('setup called!!'); log('config -> ', config); } setup(); `; const isolate = new ivm.Isolate({ memoryLimit: 128 }) const context = isolate.createContextSync() const jail = context.global jail.setSync('global', jail.derefInto()); const config = { id: 1234, name: 'test' } jail.setSync('config', new ivm.ExternalCopy(config).copyInto()); jail.setSync('libraries', new ivm.ExternalCopy(_).copyInto()); jail.setSync('log', function(...args) { console.log(...args); }) const hostile = isolate.compileScriptSync(code) hostile.run(context).catch(err => console.error(err)); } catch(e) { console.log('err->', e) } }) ()
期望:能够在setup()函数中访问libraries(即lodash模块)的内容
解决方案
报错原因
isolated-vm的ExternalCopy仅支持克隆可序列化的值(如原始类型、普通对象、数组,以及部分可转移对象)。你导入的_是ES模块对象,这类对象包含模块元数据、内部引用等不可序列化的内容,因此无法直接通过ExternalCopy传递。
可行解决方法
1. 传递模块的导出内容而非整个模块对象
对于ES模块(比如lodash-es),实际工具函数都在它的default导出中。提取这部分内容传递给Isolate即可:
修改代码中传递lodash的部分:
// 替换原有的模块对象传递代码 jail.setSync('libraries', new ivm.ExternalCopy(_.default).copyInto());
之后在隔离脚本中可正常调用lodash方法:
let code = ` async function setup() { log('setup called!!'); log('config -> ', config); // 使用lodash的map方法 log('lodash map test: ', libraries.map([1,2,3], n => n*2)); } setup(); `;
2. 在Isolate内部直接加载模块
如果Isolate配置允许访问文件系统,可在隔离环境内直接加载第三方模块,无需从外部传递。
示例:使用compileModule编译ES模块脚本
const moduleCode = ` import _ from 'lodash-es'; export async function setup() { log('setup called!!'); log('lodash version: ', _.VERSION); } `; const module = await isolate.compileModule(moduleCode); module.instantiate(context, (specifier) => { // 处理模块解析,返回对应模块的导出 if (specifier === 'lodash-es') { return ivm.Reference.from(_.default); } throw new Error(`Unsupported module: ${specifier}`); }); await module.evaluate(); const setup = module.namespace.getSync('setup'); await setup.call(context);
3. 手动提取需要的模块部分
如果仅需模块中的特定函数或对象,可手动提取后传递,避免传递整个模块:
// 只传递lodash的map和get方法 const neededLodash = { map: _.default.map, get: _.default.get }; jail.setSync('libraries', new ivm.ExternalCopy(neededLodash).copyInto());
内容的提问来源于stack exchange,提问作者Arulmani Balakrishnan
相关产品推荐
相关产品推荐

