Skip to content

Commit 84fd829

Browse files
devsnekBridgeAR
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 fce8c4e commit 84fd829

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
@@ -73,7 +73,6 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
7373
const manifest = getOptionValue('--experimental-policy') ?
7474
require('internal/process/policy').manifest :
7575
null;
76-
const { compileFunction } = internalBinding('contextify');
7776

7877
// Whether any user-provided CJS modules had been loaded (executed).
7978
// Used for internal assertions.
@@ -1045,40 +1044,25 @@ function wrapSafe(filename, content, cjsModuleInstance) {
10451044
},
10461045
});
10471046
}
1048-
let compiled;
10491047
try {
1050-
compiled = compileFunction(
1051-
content,
1048+
return vm.compileFunction(content, [
1049+
'exports',
1050+
'require',
1051+
'module',
1052+
'__filename',
1053+
'__dirname',
1054+
], {
10521055
filename,
1053-
0,
1054-
0,
1055-
undefined,
1056-
false,
1057-
undefined,
1058-
[],
1059-
[
1060-
'exports',
1061-
'require',
1062-
'module',
1063-
'__filename',
1064-
'__dirname',
1065-
]
1066-
);
1056+
importModuleDynamically(specifier) {
1057+
const loader = asyncESM.ESMLoader;
1058+
return loader.import(specifier, normalizeReferrerURL(filename));
1059+
},
1060+
});
10671061
} catch (err) {
10681062
if (process.mainModule === cjsModuleInstance)
10691063
enrichCJSError(err);
10701064
throw err;
10711065
}
1072-
1073-
const { callbackMap } = internalBinding('module_wrap');
1074-
callbackMap.set(compiled.cacheKey, {
1075-
importModuleDynamically: async (specifier) => {
1076-
const loader = asyncESM.ESMLoader;
1077-
return loader.import(specifier, normalizeReferrerURL(filename));
1078-
}
1079-
});
1080-
1081-
return compiled.function;
10821066
}
10831067

10841068
// 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)