Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8c9e3a9

Browse files
jkremscodebytere
authored andcommittedJun 18, 2020
module: remove dynamicInstantiate loader hook
The dynamicInstantiate loader hook requires that the hooks run in the same global scope as the code being loaded. We don't want to commit to this being true in the future. It stops us from sharing hooks between multiple worker threads or isolating loader hook from the application code. Using `getSource` and `getGlobalPreloadCode` the same use cases should be covered. PR-URL: #33501 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Guy Bedford <[email protected]> Reviewed-By: Bradley Farias <[email protected]>
1 parent da5e970 commit 8c9e3a9

File tree

7 files changed

+60
-111
lines changed

7 files changed

+60
-111
lines changed
 

‎doc/api/errors.md

-14
Original file line numberDiff line numberDiff line change
@@ -1570,14 +1570,6 @@ strict compliance with the API specification (which in some cases may accept
15701570
`func(undefined)` and `func()` are treated identically, and the
15711571
[`ERR_INVALID_ARG_TYPE`][] error code may be used instead.
15721572

1573-
<a id="ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK"></a>
1574-
### `ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK`
1575-
1576-
> Stability: 1 - Experimental
1577-
1578-
An [ES Module][] loader hook specified `format: 'dynamic'` but did not provide
1579-
a `dynamicInstantiate` hook.
1580-
15811573
<a id="ERR_MISSING_OPTION"></a>
15821574
### `ERR_MISSING_OPTION`
15831575

@@ -2519,12 +2511,6 @@ while trying to read and parse it.
25192511
25202512
The `--entry-type=...` flag is not compatible with the Node.js REPL.
25212513

2522-
<a id="ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK"></a>
2523-
#### `ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK`
2524-
2525-
Used when an [ES Module][] loader hook specifies `format: 'dynamic'` but does
2526-
not provide a `dynamicInstantiate` hook.
2527-
25282514
<a id="ERR_FEATURE_UNAVAILABLE_ON_PLATFORM"></a>
25292515
#### `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`
25302516

‎doc/api/esm.md

-35
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@ of the following:
12041204
| --- | --- | --- |
12051205
| `'builtin'` | Load a Node.js builtin module | Not applicable |
12061206
| `'commonjs'` | Load a Node.js CommonJS module | Not applicable |
1207-
| `'dynamic'` | Use a [dynamic instantiate hook][] | Not applicable |
12081207
| `'json'` | Load a JSON file | { [ArrayBuffer][], [string][], [TypedArray][] } |
12091208
| `'module'` | Load an ES module | { [ArrayBuffer][], [string][], [TypedArray][] } |
12101209
| `'wasm'` | Load a WebAssembly module | { [ArrayBuffer][], [string][], [TypedArray][] } |
@@ -1345,38 +1344,6 @@ const require = createRequire(process.cwd() + '/<preload>');
13451344
}
13461345
```
13471346
1348-
#### <code>dynamicInstantiate</code> hook
1349-
1350-
> Note: The loaders API is being redesigned. This hook may disappear or its
1351-
> signature may change. Do not rely on the API described below.
1352-
1353-
To create a custom dynamic module that doesn't correspond to one of the
1354-
existing `format` interpretations, the `dynamicInstantiate` hook can be used.
1355-
This hook is called only for modules that return `format: 'dynamic'` from
1356-
the [`getFormat` hook][].
1357-
1358-
```js
1359-
/**
1360-
* @param {string} url
1361-
* @returns {object} response
1362-
* @returns {array} response.exports
1363-
* @returns {function} response.execute
1364-
*/
1365-
export async function dynamicInstantiate(url) {
1366-
return {
1367-
exports: ['customExportName'],
1368-
execute: (exports) => {
1369-
// Get and set functions provided for pre-allocated export names
1370-
exports.customExportName.set('value');
1371-
}
1372-
};
1373-
}
1374-
```
1375-
1376-
With the list of module exports provided upfront, the `execute` function will
1377-
then be called at the exact point of module evaluation order for that module
1378-
in the import tree.
1379-
13801347
### Examples
13811348
13821349
The various loader hooks can be used together to accomplish wide-ranging
@@ -1846,7 +1813,6 @@ success!
18461813
[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
18471814
[`esm`]: https://github.com/standard-things/esm#readme
18481815
[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
1849-
[`getFormat` hook]: #esm_code_getformat_code_hook
18501816
[`import()`]: #esm_import_expressions
18511817
[`import.meta.url`]: #esm_import_meta
18521818
[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
@@ -1859,7 +1825,6 @@ success!
18591825
[TypedArray]: http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects
18601826
[Uint8Array]: http://www.ecma-international.org/ecma-262/6.0/#sec-uint8array
18611827
[`util.TextDecoder`]: util.html#util_class_util_textdecoder
1862-
[dynamic instantiate hook]: #esm_code_dynamicinstantiate_code_hook
18631828
[import an ES or CommonJS module for its side effects only]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_module_for_its_side_effects_only
18641829
[special scheme]: https://url.spec.whatwg.org/#special-scheme
18651830
[the full specifier path]: #esm_mandatory_file_extensions

‎lib/internal/errors.js

-3
Original file line numberDiff line numberDiff line change
@@ -1258,9 +1258,6 @@ E('ERR_MISSING_ARGS',
12581258
}
12591259
return `${msg} must be specified`;
12601260
}, TypeError);
1261-
E('ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK',
1262-
'The ES Module loader may not return a format of \'dynamic\' when no ' +
1263-
'dynamicInstantiate function was provided', Error);
12641261
E('ERR_MISSING_OPTION', '%s is required', TypeError);
12651262
E('ERR_MODULE_NOT_FOUND', (path, base, type = 'package') => {
12661263
return `Cannot find ${type} '${path}' imported from ${base}`;

‎lib/internal/modules/esm/loader.js

+5-36
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const {
1111
ERR_INVALID_RETURN_PROPERTY,
1212
ERR_INVALID_RETURN_PROPERTY_VALUE,
1313
ERR_INVALID_RETURN_VALUE,
14-
ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK,
1514
ERR_UNKNOWN_MODULE_FORMAT
1615
} = require('internal/errors').codes;
1716
const { URL, pathToFileURL } = require('internal/url');
@@ -28,14 +27,10 @@ const { defaultGetSource } = require(
2827
'internal/modules/esm/get_source');
2928
const { defaultTransformSource } = require(
3029
'internal/modules/esm/transform_source');
31-
const createDynamicModule = require(
32-
'internal/modules/esm/create_dynamic_module');
3330
const { translators } = require(
3431
'internal/modules/esm/translators');
3532
const { getOptionValue } = require('internal/options');
3633

37-
const debug = require('internal/util/debuglog').debuglog('esm');
38-
3934
/* A Loader instance is used as the main entry point for loading ES modules.
4035
* Currently, this is a singleton -- there is only one used for loading
4136
* the main module and everything in its dependency graph. */
@@ -68,23 +63,13 @@ class Loader {
6863
// This hook is called after the module is resolved but before a translator
6964
// is chosen to load it; the format returned by this function is the name
7065
// of a translator.
71-
// If `.format` on the returned value is 'dynamic', .dynamicInstantiate
72-
// will be used as described below.
7366
this._getFormat = defaultGetFormat;
7467
// This hook is called just before the source code of an ES module file
7568
// is loaded.
7669
this._getSource = defaultGetSource;
7770
// This hook is called just after the source code of an ES module file
7871
// is loaded, but before anything is done with the string.
7972
this._transformSource = defaultTransformSource;
80-
// This hook is only called when getFormat is 'dynamic' and
81-
// has the signature
82-
// (url : string) -> Promise<{ exports: { ... }, execute: function }>
83-
// Where `exports` is an object whose property names define the exported
84-
// names of the generated module. `execute` is a function that receives
85-
// an object with the same keys as `exports`, whose values are get/set
86-
// functions for the actual exported values.
87-
this._dynamicInstantiate = undefined;
8873
// The index for assigning unique URLs to anonymous module evaluation
8974
this.evalIndex = 0;
9075
}
@@ -138,7 +123,6 @@ class Loader {
138123
}
139124

140125
if (this._resolve === defaultResolve &&
141-
format !== 'dynamic' &&
142126
!url.startsWith('file:') &&
143127
!url.startsWith('data:')
144128
) {
@@ -193,8 +177,8 @@ class Loader {
193177
if (resolve !== undefined)
194178
this._resolve = FunctionPrototypeBind(resolve, null);
195179
if (dynamicInstantiate !== undefined) {
196-
this._dynamicInstantiate =
197-
FunctionPrototypeBind(dynamicInstantiate, null);
180+
process.emitWarning(
181+
'The dynamicInstantiate loader hook has been removed.');
198182
}
199183
if (getFormat !== undefined) {
200184
this._getFormat = FunctionPrototypeBind(getFormat, null);
@@ -248,25 +232,10 @@ class Loader {
248232
if (job !== undefined)
249233
return job;
250234

251-
let loaderInstance;
252-
if (format === 'dynamic') {
253-
if (typeof this._dynamicInstantiate !== 'function')
254-
throw new ERR_MISSING_DYNAMIC_INSTANTIATE_HOOK();
255-
256-
loaderInstance = async (url) => {
257-
debug(`Translating dynamic ${url}`);
258-
const { exports, execute } = await this._dynamicInstantiate(url);
259-
return createDynamicModule([], exports, url, (reflect) => {
260-
debug(`Loading dynamic ${url}`);
261-
execute(reflect.exports);
262-
}).module;
263-
};
264-
} else {
265-
if (!translators.has(format))
266-
throw new ERR_UNKNOWN_MODULE_FORMAT(format);
235+
if (!translators.has(format))
236+
throw new ERR_UNKNOWN_MODULE_FORMAT(format);
267237

268-
loaderInstance = translators.get(format);
269-
}
238+
const loaderInstance = translators.get(format);
270239

271240
const inspectBrk = parentURL === undefined &&
272241
format === 'module' && getOptionValue('--inspect-brk');

‎test/es-module/test-esm-loader-missing-dynamic-instantiate-hook.mjs

-8
This file was deleted.
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Flags: --experimental-loader ./test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs
22
import '../common/index.mjs';
3-
import { readFile } from 'fs';
3+
import { readFile, __fromLoader } from 'fs';
44
import assert from 'assert';
55
import ok from '../fixtures/es-modules/test-esm-ok.mjs';
66

77
assert(ok);
88
assert(readFile);
9+
assert(__fromLoader);
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,62 @@
11
import module from 'module';
22

3-
export function getFormat(url, context, defaultGetFormat) {
4-
if (module.builtinModules.includes(url)) {
3+
const GET_BUILTIN = `$__get_builtin_hole_${Date.now()}`;
4+
5+
export function getGlobalPreloadCode() {
6+
return `Object.defineProperty(globalThis, ${JSON.stringify(GET_BUILTIN)}, {
7+
value: (builtinName) => {
8+
return getBuiltin(builtinName);
9+
},
10+
enumerable: false,
11+
configurable: false,
12+
});
13+
`;
14+
}
15+
16+
export function resolve(specifier, context, defaultResolve) {
17+
const def = defaultResolve(specifier, context);
18+
if (def.url.startsWith('nodejs:')) {
19+
return {
20+
url: `custom-${def.url}`,
21+
};
22+
}
23+
return def;
24+
}
25+
26+
export function getSource(url, context, defaultGetSource) {
27+
if (url.startsWith('custom-nodejs:')) {
28+
const urlObj = new URL(url);
529
return {
6-
format: 'dynamic'
30+
source: generateBuiltinModule(urlObj.pathname),
31+
format: 'module',
732
};
833
}
34+
return defaultGetSource(url, context);
35+
}
36+
37+
export function getFormat(url, context, defaultGetFormat) {
38+
if (url.startsWith('custom-nodejs:')) {
39+
return { format: 'module' };
40+
}
941
return defaultGetFormat(url, context, defaultGetFormat);
1042
}
1143

12-
export function dynamicInstantiate(url) {
13-
const builtinInstance = module._load(url);
14-
const builtinExports = ['default', ...Object.keys(builtinInstance)];
15-
return {
16-
exports: builtinExports,
17-
execute: exports => {
18-
for (let name of builtinExports)
19-
exports[name].set(builtinInstance[name]);
20-
exports.default.set(builtinInstance);
21-
}
22-
};
44+
function generateBuiltinModule(builtinName) {
45+
const builtinInstance = module._load(builtinName);
46+
const builtinExports = [
47+
...Object.keys(builtinInstance),
48+
];
49+
return `\
50+
const $builtinInstance = ${GET_BUILTIN}(${JSON.stringify(builtinName)});
51+
52+
export const __fromLoader = true;
53+
54+
export default $builtinInstance;
55+
56+
${
57+
builtinExports
58+
.map(name => `export const ${name} = $builtinInstance.${name};`)
59+
.join('\n')
60+
}
61+
`;
2362
}

0 commit comments

Comments
 (0)
Please sign in to comment.