Pierre Arlaud Pierre Arlaud - 4 months ago 18
Node.js Question

Pass functions in a vm script context

Let's say I have a library module that looks like this:

module.exports = {
increment: function() {
count++;
}
}


And I'd like to use it in a dynamically generated script that looks like this:

(function() { lib.increment(); })();


by passing it in a sandbox:

var sandbox = {
count: 1
lib: require('./lib')
}
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);


The obvious problem I run into is that I on the one hand can't require "lib" because "count" is not defined in lib.js ; on the other hand if I define
var count
above the exports of the "lib.js" file, this new
count
variable will be affected instead of the one in the sandbox.

Here are the constraints that I would like to respect:


  • Use vm and not a eval() nor a require() on a generated file

  • Have "lib" defined in a external file

  • No modification of the automatically generated script, so no use of
    lib.increment.apply(context)
    or similar



The only solutions I've found so far is to prepend the
lib
functions in the generated script as a string, or to define them directly on the
sandbox
object, which I find to be a less desirable option.

There doesn't seem to be any way of passing a context of variables on the
require
call.

Answer

One way of accomplishing this is have your lib module be a function that takes in a context then returns the correct interface.

lib.js

module.exports = function(context) {
  var count = context.count;
  return {
    increment: function() {
      count++;
    }
  };
};

main.js

var sandbox = {
  count: 1
};
sandbox.lib = require('./lib')(sandbox);
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);