Require 在 vm 中没有按预期工作

Require does not work as expected within vm

下面的代码使用本机节点 vm 库,它允许您在不同的上下文中评估 javascript 字符串。

example.js 中的特定代码有一个 javascript 字符串,它添加一个 属性 .markertrueArray全局变量,然后需要文件 global.js(见下文),然后记录 Array.marker。下面的代码记录 true.

var vm = require('vm')

var code = [
  'Array.marker = true',
  "require('./global.js')",
  'console.log(Array.marker)', // => true
].join('\n')

var script = new vm.Script(code, { filename: 'example.js' })

script.runInNewContext({
  'require': require,
  'console': console
})

下面是global.js的内容,是一个简单的模块,将Array.marker的值改为false

var hi = function () {
  Array.marker = false
}
module.exports = hi()

这里应该发生的是 vm 中的代码应该将 Array.marker 设置为 true 然后 global.js 模块应该将其值更改为false 并且它应该记录 false

如果你继续 运行 vm 之外的 javascript 字符串的内容,在它自己的文件中,你将得到预期的结果,Array.marker将等于 false

Array.marker = true
require('./global.js')
console.log(Array.marker) // => false

问题是:为什么 Array.marker 没有更新为正确的值 (true)? 我怎样才能允许从 global.js 模块中更新 Array.marker 的值?

这是原生 node.js vm 模块的问题吗?或者这不应该是可能的?还是我的设置关闭了?

更新:

我认为这个错误有点深。它与导入的 require 的行为有关,然后与 vm 的行为有关,以更准确地证明这一点。

在这里,我在一个新的 vm 上下文中更改了 Array.marker 的值,您可以看到它对 vm 运行 之后的全局 Array.marker 没有影响。这是预期的行为,因为我没有将任何内容传递给 vm.

var vm = require('vm')
var code = [
  'Array.marker = true',
].join('\n')
vm.runInNewContext(code)
console.log(Array.marker) // => undefined [expected]

然而,当我将 require 带入 vm 时,一些意想不到的事情发生了。所需的代码维护父上下文的范围。因此,使用给定的代码,您会得到意想不到的结果。由于 require 调用,vm 脚本中的全局 Array.marker 没有改变,您可以看到 require 调用正在通过设置 Array.marker.

来编辑父作用域
var vm = require('vm')
var code = [
  'Array.marker = true',
  "require(\'./global.js\')",
  'console.log(Array.marker)' // => true [unexpected]
].join('\n')
vm.runInNewContext(code, {
  require: require,
  console: console
})
console.log(Array.marker) // => false [unexpected]

真正的问题是如何在 vm 中实例化 require 的新实例,而不是导入父实例?将其本地化到 vm 而不是让它泄漏到父级中。

这样的东西行得通吗?

var gbl = require('./global.js');

scriptText = "Array.marker = true; gbl(Array.marker);"

var context = vm.createContext();
var script = vm.createScript(scriptText); 
var fn = script.runInContext(context);
fn(gbl);

您需要更改 global.js 中的函数以接受 Array.marker 作为参数。