Skip to content

Commit

Permalink
module: fix dynamic import from eval
Browse files Browse the repository at this point in the history
This allows dynamic import to work from CLI `--eval` with or without
`--input-type=module`.

Fixes: nodejs#30591
  • Loading branch information
coreyfarrell committed Dec 6, 2019
1 parent 51ccf1b commit da3f505
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
13 changes: 11 additions & 2 deletions lib/internal/modules/esm/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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();
Expand Down
18 changes: 17 additions & 1 deletion lib/internal/process/execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)};
Expand All @@ -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) {
Expand Down
20 changes: 20 additions & 0 deletions test/parallel/test-cli-eval.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}));

0 comments on commit da3f505

Please sign in to comment.