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: #30591

PR-URL: #30624
Reviewed-By: Gus Caplan <[email protected]>
Reviewed-By: Yorkie Liu <[email protected]>
Reviewed-By: Ben Coe <[email protected]>
  • Loading branch information
coreyfarrell authored and BethGriggs committed Feb 6, 2020
1 parent 77c69f5 commit cad5c2b
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 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 @@ -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');
Expand Down Expand Up @@ -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();
Expand Down
15 changes: 13 additions & 2 deletions lib/internal/process/execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,38 @@ 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.

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) {
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} ${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');
}));

0 comments on commit cad5c2b

Please sign in to comment.