diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index c98ea20798..2291679099 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -371,7 +371,6 @@ enumerable: false, configurable: true }); - global.process = process; const util = NativeModule.require('util'); function makeGetter(name) { @@ -408,7 +407,6 @@ // and exposes it on `internal/buffer`. NativeModule.require('internal/buffer'); - global.Buffer = NativeModule.require('buffer').Buffer; process.domain = null; process._exiting = false; } @@ -601,9 +599,12 @@ 'global.module = module;\n' + 'global.__dirname = __dirname;\n' + 'global.require = require;\n' + + 'global.process = process;\n' + + 'global.Buffer = Buffer;\n' + 'return require("vm").runInThisContext(' + `${JSON.stringify(body)}, { filename: ` + `${JSON.stringify(name)}, displayErrors: true });\n`; + const result = module._compile(script, `${name}-wrapper`); if (process._print_eval) console.log(result); // Handle any nextTicks added in the first tick of the program. diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js index 5b5199c262..389bfdc31c 100644 --- a/lib/internal/modules/cjs/helpers.js +++ b/lib/internal/modules/cjs/helpers.js @@ -100,9 +100,9 @@ function stripShebang(content) { const builtinLibs = [ 'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'net', - 'os', 'path', 'perf_hooks', 'punycode', 'querystring', 'readline', 'repl', - 'stream', 'string_decoder', 'tls', 'trace_events', 'tty', 'url', 'util', - 'v8', 'vm', 'zlib' + 'os', 'path', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline', + 'repl', 'stream', 'string_decoder', 'tls', 'trace_events', 'tty', 'url', + 'util', 'v8', 'vm', 'zlib' ]; if (process.binding('config').experimentalWorker) { diff --git a/lib/internal/modules/cjs/isstrict.js b/lib/internal/modules/cjs/isstrict.js new file mode 100644 index 0000000000..d250259a9b --- /dev/null +++ b/lib/internal/modules/cjs/isstrict.js @@ -0,0 +1,7 @@ +/* eslint-disable strict no-global-assign */ +try { + NaN = undefined; + module.exports = false; +} catch (e) { + module.exports = true; +} diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index c218dc2cac..56acb85ac0 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -42,6 +42,8 @@ const { const preserveSymlinks = !!process.binding('config').preserveSymlinks; const preserveSymlinksMain = !!process.binding('config').preserveSymlinksMain; const experimentalModules = !!process.binding('config').experimentalModules; +const { Buffer } = require('buffer'); +const isStrict = require('internal/modules/cjs/isstrict'); const { ERR_INVALID_ARG_TYPE, @@ -126,8 +128,9 @@ Module.wrap = function(script) { }; Module.wrapper = [ - '(function (exports, require, module, __filename, __dirname) { ', - '\n});' + (isStrict ? '(' : '(function (global) { with (global) { return ') + + 'function (exports, require, module, __filename, __dirname) { ', + '\n}' + (isStrict ? ');' : ';\n}\n});') ]; const debug = util.debuglog('module'); @@ -642,6 +645,72 @@ Module.prototype.require = function(id) { // (needed for setting breakpoint when called with --inspect-brk) var resolvedArgv; +let globalContext; +if (isStrict) { + // we cannot properly proxy Buffer and process in strict mode + global.process = process; + global.Buffer = Buffer; + globalContext = global; +} else { + let bufferWritten = false; + let processWritten = false; + let globalWritten = false; + globalContext = new Proxy(global, { + get(target, prop, receiver) { + if (!bufferWritten && prop === 'Buffer') + return Buffer; + if (!processWritten && prop === 'process') + return process; + if (!globalWritten && (prop === 'global' || prop === 'GLOBAL')) + return globalContext; + return Reflect.get(target, prop, receiver); + }, + has(target, prop) { + if (!bufferWritten && prop === 'Buffer' || + !processWritten && prop === 'process' || + !globalWritten && (prop === 'global' || prop === 'GLOBAL')) + return true; + return prop in target; + }, + set(target, prop, value, receiver) { + if (prop === 'Buffer') + bufferWritten = true; + else if (prop === 'process') + processWritten = true; + else if (prop === 'global' || prop === 'GLOBAL') + globalWritten = true; + return Reflect.set(target, prop, value, receiver); + }, + deleteProperty(target, prop) { + if (prop === 'Buffer') + bufferWritten = true; + else if (prop === 'process') + processWritten = true; + else if (prop === 'global' || prop === 'GLOBAL') + globalWritten = true; + return delete target[prop]; + }, + defineProperty(target, prop, descriptor) { + if (prop === 'Buffer') + bufferWritten = true; + else if (prop === 'process') + processWritten = true; + else if (prop === 'global' || prop === 'GLOBAL') + globalWritten = true; + return Object.defineProperty(target, prop, descriptor); + }, + ownKeys(target) { + const keys = Reflect.ownKeys(target); + if (!processWritten && !bufferWritten) + keys.splice(keys.indexOf('clearImmediate'), 0, 'process', 'Buffer'); + else if (!processWritten) + keys.splice(keys.indexOf('clearImmediate'), 0, 'process'); + else if (!bufferWritten) + keys.splice(keys.indexOf('clearImmediate'), 0, 'Buffer'); + return keys; + } + }); +} // Run the file contents in the correct scope or sandbox. Expose // the correct helper variables (require, module, exports) to @@ -660,6 +729,10 @@ Module.prototype._compile = function(content, filename) { displayErrors: true }); + if (!isStrict) { + compiledWrapper = compiledWrapper(globalContext); + } + var inspectorWrapper = null; if (process._breakFirstLine && process._eval == null) { if (!resolvedArgv) { diff --git a/node.gyp b/node.gyp index 5b8ca26bb2..f7fc0ae027 100644 --- a/node.gyp +++ b/node.gyp @@ -123,6 +123,7 @@ 'lib/internal/inspector_async_hook.js', 'lib/internal/linkedlist.js', 'lib/internal/modules/cjs/helpers.js', + 'lib/internal/modules/cjs/isstrict.js', 'lib/internal/modules/cjs/loader.js', 'lib/internal/modules/esm/loader.js', 'lib/internal/modules/esm/create_dynamic_module.js', diff --git a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs index 28ccd6ecf2..ac2a800938 100644 --- a/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs +++ b/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs @@ -1,4 +1,5 @@ import module from 'module'; +import process from 'process'; const builtins = new Set( Object.keys(process.binding('natives')).filter(str => diff --git a/test/fixtures/es-module-loaders/js-loader.mjs b/test/fixtures/es-module-loaders/js-loader.mjs index 9fa6b9eed4..f6b9acad56 100644 --- a/test/fixtures/es-module-loaders/js-loader.mjs +++ b/test/fixtures/es-module-loaders/js-loader.mjs @@ -1,4 +1,5 @@ import { URL } from 'url'; +import process from 'process'; const builtins = new Set( Object.keys(process.binding('natives')).filter(str =>