From cad5c2bc6e0b9478b445a02d98107f8257bc8621 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 23 Nov 2019 00:45:10 -0500 Subject: [PATCH] module: fix dynamic import from eval This allows dynamic import to work from CLI `--eval` with or without `--input-type=module`. Fixes: https://github.com/nodejs/node/issues/30591 PR-URL: https://github.com/nodejs/node/pull/30624 Reviewed-By: Gus Caplan Reviewed-By: Yorkie Liu Reviewed-By: Ben Coe --- lib/internal/modules/esm/loader.js | 13 +++++++++++-- lib/internal/process/execution.js | 15 +++++++++++++-- test/parallel/test-cli-eval.js | 20 ++++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 875fb97f912a85..644c13dbe5d6cb 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -21,7 +21,6 @@ const defaultResolve = require('internal/modules/esm/default_resolve'); const createDynamicModule = require( 'internal/modules/esm/create_dynamic_module'); const { translators } = require('internal/modules/esm/translators'); -const { ModuleWrap } = internalBinding('module_wrap'); const { getOptionValue } = require('internal/options'); const debug = require('internal/util/debuglog').debuglog('esm'); @@ -118,7 +117,17 @@ class Loader { source, url = pathToFileURL(`${process.cwd()}/[eval${++this.evalIndex}]`).href ) { - const evalInstance = (url) => new ModuleWrap(url, undefined, source, 0, 0); + const evalInstance = (url) => { + const { ModuleWrap, callbackMap } = internalBinding('module_wrap'); + const module = new ModuleWrap(url, undefined, source, 0, 0); + callbackMap.set(module, { + importModuleDynamically: (specifier, { url }) => { + return this.import(specifier, url); + } + }); + + return module; + }; const job = new ModuleJob(this, url, evalInstance, false, false); this.moduleMap.set(url, job); const { module, result } = await job.run(); diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index eed554263c213c..8e8c46872114cb 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -55,6 +55,7 @@ function evalModule(source, print) { function evalScript(name, body, breakFirstLine, print) { const CJSModule = require('internal/modules/cjs/loader').Module; const { kVmBreakFirstLineSymbol } = require('internal/util'); + const { pathToFileURL } = require('url'); const cwd = tryGetCwd(); const origModule = global.module; // Set e.g. when called from the REPL. @@ -62,20 +63,30 @@ function evalScript(name, body, breakFirstLine, print) { const module = new CJSModule(name); module.filename = path.join(cwd, name); module.paths = CJSModule._nodeModulePaths(cwd); + global.kVmBreakFirstLineSymbol = kVmBreakFirstLineSymbol; + global.asyncESM = require('internal/process/esm_loader'); + + const baseUrl = pathToFileURL(module.filename).href; + const script = ` global.__filename = ${JSON.stringify(name)}; global.exports = exports; global.module = module; global.__dirname = __dirname; global.require = require; - const { kVmBreakFirstLineSymbol } = global; + const { kVmBreakFirstLineSymbol, asyncESM } = global; delete global.kVmBreakFirstLineSymbol; + delete global.asyncESM; return require("vm").runInThisContext( ${JSON.stringify(body)}, { filename: ${JSON.stringify(name)}, displayErrors: true, - [kVmBreakFirstLineSymbol]: ${!!breakFirstLine} + [kVmBreakFirstLineSymbol]: ${!!breakFirstLine}, + async importModuleDynamically (specifier) { + const loader = await asyncESM.ESMLoader; + return loader.import(specifier, ${JSON.stringify(baseUrl)}); + } });\n`; const result = module._compile(script, `${name}-wrapper`); if (print) { diff --git a/test/parallel/test-cli-eval.js b/test/parallel/test-cli-eval.js index 0d2ea48c06fa39..71482205932a27 100644 --- a/test/parallel/test-cli-eval.js +++ b/test/parallel/test-cli-eval.js @@ -283,3 +283,23 @@ child.exec( assert.ifError(err); assert.strictEqual(stdout, '.mjs file\n'); })); + + +// Assert that packages can be dynamic imported initial cwd-relative with --eval +child.exec( + `${nodejs} ${execOptions} ` + + '--eval "process.chdir(\'..\');' + + 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', + common.mustCall((err, stdout) => { + assert.ifError(err); + assert.strictEqual(stdout, '.mjs file\n'); + })); + +child.exec( + `${nodejs} ${execOptions} ` + + '--eval "process.chdir(\'..\');' + + 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', + common.mustCall((err, stdout) => { + assert.ifError(err); + assert.strictEqual(stdout, '.mjs file\n'); + }));