Skip to content

Commit 4143c74

Browse files
devsnekBethGriggs
authored andcommitted
vm: add importModuleDynamically option to compileFunction
Fixes: #31860 PR-URL: #32985 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent c21f1f0 commit 4143c74

File tree

5 files changed

+63
-30
lines changed

5 files changed

+63
-30
lines changed

doc/api/vm.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ changes:
8888
This option is part of the experimental modules API, and should not be
8989
considered stable.
9090
* `specifier` {string} specifier passed to `import()`
91-
* `module` {vm.Module}
91+
* `script` {vm.Script}
9292
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
9393
recommended in order to take advantage of error tracking, and to avoid
9494
issues with namespaces that contain `then` function exports.
@@ -773,6 +773,10 @@ const vm = require('vm');
773773
## `vm.compileFunction(code[, params[, options]])`
774774
<!-- YAML
775775
added: v10.10.0
776+
changes:
777+
- version: REPLACEME
778+
pr-url: https://github.com/nodejs/node/pull/32985
779+
description: The `importModuleDynamically` option is now supported.
776780
-->
777781

778782
* `code` {string} The body of the function to compile.
@@ -795,6 +799,16 @@ added: v10.10.0
795799
* `contextExtensions` {Object[]} An array containing a collection of context
796800
extensions (objects wrapping the current scope) to be applied while
797801
compiling. **Default:** `[]`.
802+
* `importModuleDynamically` {Function} Called during evaluation of this module
803+
when `import()` is called. If this option is not specified, calls to
804+
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
805+
This option is part of the experimental modules API, and should not be
806+
considered stable.
807+
* `specifier` {string} specifier passed to `import()`
808+
* `function` {Function}
809+
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
810+
recommended in order to take advantage of error tracking, and to avoid
811+
issues with namespaces that contain `then` function exports.
798812
* Returns: {Function}
799813

800814
Compiles the given code into the provided context (if no context is

lib/internal/modules/cjs/loader.js

+12-28
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
7777
const manifest = getOptionValue('--experimental-policy') ?
7878
require('internal/process/policy').manifest :
7979
null;
80-
const { compileFunction } = internalBinding('contextify');
8180

8281
// Whether any user-provided CJS modules had been loaded (executed).
8382
// Used for internal assertions.
@@ -1100,40 +1099,25 @@ function wrapSafe(filename, content, cjsModuleInstance) {
11001099
},
11011100
});
11021101
}
1103-
let compiled;
11041102
try {
1105-
compiled = compileFunction(
1106-
content,
1103+
return vm.compileFunction(content, [
1104+
'exports',
1105+
'require',
1106+
'module',
1107+
'__filename',
1108+
'__dirname',
1109+
], {
11071110
filename,
1108-
0,
1109-
0,
1110-
undefined,
1111-
false,
1112-
undefined,
1113-
[],
1114-
[
1115-
'exports',
1116-
'require',
1117-
'module',
1118-
'__filename',
1119-
'__dirname',
1120-
]
1121-
);
1111+
importModuleDynamically(specifier) {
1112+
const loader = asyncESM.ESMLoader;
1113+
return loader.import(specifier, normalizeReferrerURL(filename));
1114+
},
1115+
});
11221116
} catch (err) {
11231117
if (process.mainModule === cjsModuleInstance)
11241118
enrichCJSError(err);
11251119
throw err;
11261120
}
1127-
1128-
const { callbackMap } = internalBinding('module_wrap');
1129-
callbackMap.set(compiled.cacheKey, {
1130-
importModuleDynamically: async (specifier) => {
1131-
const loader = asyncESM.ESMLoader;
1132-
return loader.import(specifier, normalizeReferrerURL(filename));
1133-
}
1134-
});
1135-
1136-
return compiled.function;
11371121
}
11381122

11391123
// Run the file contents in the correct scope or sandbox. Expose

lib/vm.js

+17
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ function compileFunction(code, params, options = {}) {
313313
produceCachedData = false,
314314
parsingContext = undefined,
315315
contextExtensions = [],
316+
importModuleDynamically,
316317
} = options;
317318

318319
validateString(filename, 'options.filename');
@@ -360,6 +361,22 @@ function compileFunction(code, params, options = {}) {
360361
result.function.cachedData = result.cachedData;
361362
}
362363

364+
if (importModuleDynamically !== undefined) {
365+
if (typeof importModuleDynamically !== 'function') {
366+
throw new ERR_INVALID_ARG_TYPE('options.importModuleDynamically',
367+
'function',
368+
importModuleDynamically);
369+
}
370+
const { importModuleDynamicallyWrap } =
371+
require('internal/vm/module');
372+
const { callbackMap } = internalBinding('module_wrap');
373+
const wrapped = importModuleDynamicallyWrap(importModuleDynamically);
374+
const func = result.function;
375+
callbackMap.set(result.cacheKey, {
376+
importModuleDynamically: (s, _k) => wrapped(s, func),
377+
});
378+
}
379+
363380
return result.function;
364381
}
365382

test/parallel/test-vm-module-basic.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const {
88
Module,
99
SourceTextModule,
1010
SyntheticModule,
11-
createContext
11+
createContext,
12+
compileFunction,
1213
} = require('vm');
1314
const util = require('util');
1415

@@ -147,3 +148,19 @@ const util = require('util');
147148
name: 'TypeError'
148149
});
149150
}
151+
152+
// Test compileFunction importModuleDynamically
153+
{
154+
const module = new SyntheticModule([], () => {});
155+
module.link(() => {});
156+
const f = compileFunction('return import("x")', [], {
157+
importModuleDynamically(specifier, referrer) {
158+
assert.strictEqual(specifier, 'x');
159+
assert.strictEqual(referrer, f);
160+
return module;
161+
},
162+
});
163+
f().then((ns) => {
164+
assert.strictEqual(ns, module.namespace);
165+
});
166+
}

tools/doc/type-parser.js

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ const customTypesMap = {
148148
'URLSearchParams': 'url.html#url_class_urlsearchparams',
149149

150150
'vm.Module': 'vm.html#vm_class_vm_module',
151+
'vm.Script': 'vm.html#vm_class_vm_script',
151152
'vm.SourceTextModule': 'vm.html#vm_class_vm_sourcetextmodule',
152153

153154
'MessagePort': 'worker_threads.html#worker_threads_class_messageport',

0 commit comments

Comments
 (0)