From da3f5054e3e5a5f42e1e52fdba40aabbcc4c4eee Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 23 Nov 2019 00:45:10 -0500 Subject: [PATCH 1/2] 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 --- lib/internal/modules/esm/loader.js | 13 +++++++++++-- lib/internal/process/execution.js | 18 +++++++++++++++++- test/parallel/test-cli-eval.js | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 97f57935292396..255e5d2aba7bd8 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -25,7 +25,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'); @@ -117,7 +116,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 44c67452f5a01f..1b24902e538b37 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -64,6 +64,19 @@ function evalScript(name, body, breakFirstLine, print) { const module = new CJSModule(name); module.filename = path.join(cwd, name); module.paths = CJSModule._nodeModulePaths(cwd); + + let fileURL; + module.importModuleDynamically = async (specifier) => { + if (!fileURL) { + const { pathToFileURL } = require('url'); + fileURL = pathToFileURL(path.join(cwd, name)).href; + } + + const asyncESM = require('internal/process/esm_loader'); + const loader = await asyncESM.ESMLoader; + return loader.import(specifier, fileURL); + }; + global.kVmBreakFirstLineSymbol = kVmBreakFirstLineSymbol; const script = ` global.__filename = ${JSONStringify(name)}; @@ -73,11 +86,14 @@ function evalScript(name, body, breakFirstLine, print) { global.require = require; const { kVmBreakFirstLineSymbol } = global; delete global.kVmBreakFirstLineSymbol; + const { importModuleDynamically } = module; + delete module.importModuleDynamically; return require("vm").runInThisContext( ${JSONStringify(body)}, { filename: ${JSONStringify(name)}, displayErrors: true, - [kVmBreakFirstLineSymbol]: ${!!breakFirstLine} + [kVmBreakFirstLineSymbol]: ${!!breakFirstLine}, + importModuleDynamically });\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 2cece62a437d52..65d31642055627 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} ` + + '--eval "process.chdir(\'..\');' + + 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', + common.mustCall((err, stdout) => { + assert.ifError(err); + assert.strictEqual(stdout, '.mjs file\n'); + })); From bcc0331b7115d7a31e09f15f148369616e4dd94b Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Thu, 5 Dec 2019 00:06:38 -0500 Subject: [PATCH 2/2] tweak importModuleDynamically inlining --- lib/internal/process/execution.js | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index 1b24902e538b37..8b15fbbae46f26 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -57,6 +57,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. @@ -65,35 +66,29 @@ function evalScript(name, body, breakFirstLine, print) { module.filename = path.join(cwd, name); module.paths = CJSModule._nodeModulePaths(cwd); - let fileURL; - module.importModuleDynamically = async (specifier) => { - if (!fileURL) { - const { pathToFileURL } = require('url'); - fileURL = pathToFileURL(path.join(cwd, name)).href; - } + global.kVmBreakFirstLineSymbol = kVmBreakFirstLineSymbol; + global.asyncESM = require('internal/process/esm_loader'); - const asyncESM = require('internal/process/esm_loader'); - const loader = await asyncESM.ESMLoader; - return loader.import(specifier, fileURL); - }; + const baseUrl = pathToFileURL(module.filename).href; - global.kVmBreakFirstLineSymbol = kVmBreakFirstLineSymbol; const script = ` global.__filename = ${JSONStringify(name)}; global.exports = exports; global.module = module; global.__dirname = __dirname; global.require = require; - const { kVmBreakFirstLineSymbol } = global; + const { kVmBreakFirstLineSymbol, asyncESM } = global; delete global.kVmBreakFirstLineSymbol; - const { importModuleDynamically } = module; - delete module.importModuleDynamically; + delete global.asyncESM; return require("vm").runInThisContext( ${JSONStringify(body)}, { filename: ${JSONStringify(name)}, displayErrors: true, [kVmBreakFirstLineSymbol]: ${!!breakFirstLine}, - importModuleDynamically + async importModuleDynamically (specifier) { + const loader = await asyncESM.ESMLoader; + return loader.import(specifier, ${JSONStringify(baseUrl)}); + } });\n`; const result = module._compile(script, `${name}-wrapper`); if (print) {