diff --git a/doc/api/vm.markdown b/doc/api/vm.markdown index 1b494a468c947d..109cd983ee200a 100644 --- a/doc/api/vm.markdown +++ b/doc/api/vm.markdown @@ -277,7 +277,7 @@ console.log('localVar: ', localVar); // vmResult: 'vm', localVar: 'initial value' // evalResult: 'eval', localVar: 'eval' ``` - + `vm.runInThisContext` does not have access to the local scope, so `localVar` is unchanged. `eval` does have access to the local scope, so `localVar` is changed. @@ -297,6 +297,31 @@ e.g. `(0,eval)('code')`. However, it also has the following additional options: - `timeout`: a number of milliseconds to execute `code` before terminating execution. If execution is terminated, an [`Error`][] will be thrown. +## vm.runInModuleContext(code[, options]) + +`vm.runInModuleContext()` compiles `code`, runs it and returns the result. Running +code does not have access to local scope, but does have access to `module`, +`exports` and `require`. You can expect the script to behave similar to scripts +in the global context e.g. requiring global modules. + +Example of using `vm.runInModuleContext` requiring `http` and a run a server: + +```js +const vm = require('vm') + +const vmResult = vm.runInModuleContext(` + const http = require('http'); + http.createServer( (request, response) => { + response.writeHead(200, {'Content-Type': 'text/plain'}); + response.end('Hello World\\n'); + }).listen(8124); + + console.log('Server running at http://127.0.0.1:8124/'); +`) +``` + +For options, see [`vm.runInThisContext()`](#runInThisContext) + [indirect `eval` call]: https://es5.github.io/#x10.4.2 [global object]: https://es5.github.io/#x15.1 [`Error`]: errors.html#errors_class_error diff --git a/lib/vm.js b/lib/vm.js index b4a2b9999091d2..4b328fabadfed4 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -54,4 +54,10 @@ exports.runInThisContext = function(code, options) { return script.runInThisContext(options); }; +exports.runInModuleContext = function(code, options) { + var script = new Script(require('module').wrap(code), options); + let passThrough = options && options.passThrough ? options.passThrough : [] + return script.runInThisContext(options).apply(null, passThrough); +}; + exports.isContext = binding.isContext; diff --git a/test/parallel/test-vm-basic.js b/test/parallel/test-vm-basic.js index 8f9cab90eb5a1b..8c86dd55c2739a 100644 --- a/test/parallel/test-vm-basic.js +++ b/test/parallel/test-vm-basic.js @@ -35,16 +35,25 @@ var result = vm.runInThisContext( ); assert.strictEqual(global.vmResult, 'foo'); assert.strictEqual(result, '[object process]'); + +// Test 4: vm.runInGlobalContext +var result = vm.runInModuleContext(` + const path = require('path') + vmResult = path.dirname('/foo/bar/baz/asdf/quux'); + Object.prototype.toString.call(process);` +); +assert.strictEqual(global.vmResult, + require('path').dirname('/foo/bar/baz/asdf/quux')); delete global.vmResult; -// Test 4: vm.runInNewContext +// Test 5: vm.runInNewContext var result = vm.runInNewContext( 'vmResult = "foo"; typeof process;' ); assert.strictEqual(global.vmResult, undefined); assert.strictEqual(result, 'undefined'); -// Test 5: vm.createContext +// Test 6: vm.createContext var sandbox3 = {}; var context2 = vm.createContext(sandbox3); assert.strictEqual(sandbox3, context2);