Skip to content

Commit f3d4fc3

Browse files
esm: remove globalPreload hook (superseded by initialize)
1 parent 982e7a6 commit f3d4fc3

File tree

8 files changed

+10
-405
lines changed

8 files changed

+10
-405
lines changed

lib/internal/modules/esm/hooks.js

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ let importMetaInitializer;
7373

7474
/**
7575
* @typedef {object} ExportedHooks
76-
* @property {Function} globalPreload Global preload hook.
76+
* @property {Function} initialize Customizations setup hook.
7777
* @property {Function} resolve Resolve hook.
7878
* @property {Function} load Load hook.
7979
*/
@@ -88,13 +88,6 @@ let importMetaInitializer;
8888

8989
class Hooks {
9090
#chains = {
91-
/**
92-
* Prior to ESM loading. These are called once before any modules are started.
93-
* @private
94-
* @property {KeyedHook[]} globalPreload Last-in-first-out list of preload hooks.
95-
*/
96-
globalPreload: [],
97-
9891
/**
9992
* Phase 1 of 2 in ESM loading.
10093
* The output of the `resolve` chain of hooks is passed into the `load` chain of hooks.
@@ -154,18 +147,11 @@ class Hooks {
154147
*/
155148
addCustomLoader(url, exports, data) {
156149
const {
157-
globalPreload,
158150
initialize,
159151
resolve,
160152
load,
161153
} = pluckHooks(exports);
162154

163-
if (globalPreload && !initialize) {
164-
emitExperimentalWarning(
165-
'`globalPreload` is planned for removal in favor of `initialize`. `globalPreload`',
166-
);
167-
ArrayPrototypePush(this.#chains.globalPreload, { __proto__: null, fn: globalPreload, url });
168-
}
169155
if (resolve) {
170156
const next = this.#chains.resolve[this.#chains.resolve.length - 1];
171157
ArrayPrototypePush(this.#chains.resolve, { __proto__: null, fn: resolve, url, next });
@@ -177,49 +163,6 @@ class Hooks {
177163
return initialize?.(data);
178164
}
179165

180-
/**
181-
* Initialize `globalPreload` hooks.
182-
*/
183-
initializeGlobalPreload() {
184-
const preloadScripts = [];
185-
for (let i = this.#chains.globalPreload.length - 1; i >= 0; i--) {
186-
const { MessageChannel } = require('internal/worker/io');
187-
const channel = new MessageChannel();
188-
const {
189-
port1: insidePreload,
190-
port2: insideLoader,
191-
} = channel;
192-
193-
insidePreload.unref();
194-
insideLoader.unref();
195-
196-
const {
197-
fn: preload,
198-
url: specifier,
199-
} = this.#chains.globalPreload[i];
200-
201-
const preloaded = preload({
202-
port: insideLoader,
203-
});
204-
205-
if (preloaded == null) { continue; }
206-
207-
if (typeof preloaded !== 'string') { // [2]
208-
throw new ERR_INVALID_RETURN_VALUE(
209-
'a string',
210-
`${specifier} globalPreload`,
211-
preload,
212-
);
213-
}
214-
215-
ArrayPrototypePush(preloadScripts, {
216-
code: preloaded,
217-
port: insidePreload,
218-
});
219-
}
220-
return preloadScripts;
221-
}
222-
223166
/**
224167
* Resolve the location of the module.
225168
*
@@ -749,9 +692,6 @@ function pluckHooks({
749692
}) {
750693
const acceptedHooks = { __proto__: null };
751694

752-
if (globalPreload) {
753-
acceptedHooks.globalPreload = globalPreload;
754-
}
755695
if (resolve) {
756696
acceptedHooks.resolve = resolve;
757697
}
@@ -761,6 +701,11 @@ function pluckHooks({
761701

762702
if (initialize) {
763703
acceptedHooks.initialize = initialize;
704+
} else if (globalPreload) { // TODO(JakobJingleheimer): Remove this when loaders go "stable".
705+
process.emitWarning(
706+
'`globalPreload` has been removed; use `initialize` instead.',
707+
'DeprecationWarning',
708+
);
764709
}
765710

766711
return acceptedHooks;

lib/internal/modules/esm/utils.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,7 @@ async function initializeHooks() {
145145
);
146146
}
147147

148-
const preloadScripts = hooks.initializeGlobalPreload();
149-
150-
return { __proto__: null, hooks, preloadScripts };
148+
return { __proto__: null, hooks };
151149
}
152150

153151
module.exports = {

test/es-module/test-esm-loader-hooks.mjs

Lines changed: 1 addition & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -422,143 +422,6 @@ describe('Loader hooks', { concurrency: true }, () => {
422422
});
423423
});
424424

425-
describe('globalPreload', () => {
426-
it('should emit deprecation warning', async () => {
427-
const { stderr } = await spawnPromisified(execPath, [
428-
'--experimental-loader',
429-
'data:text/javascript,export function globalPreload(){}',
430-
'--experimental-loader',
431-
'data:text/javascript,export function globalPreload(){return""}',
432-
fixtures.path('empty.js'),
433-
]);
434-
435-
assert.strictEqual(stderr.match(/`globalPreload` is an experimental feature/g).length, 1);
436-
});
437-
438-
it('should not emit deprecation warning when initialize is supplied', async () => {
439-
const { stderr } = await spawnPromisified(execPath, [
440-
'--experimental-loader',
441-
'data:text/javascript,export function globalPreload(){}export function initialize(){}',
442-
fixtures.path('empty.js'),
443-
]);
444-
445-
assert.doesNotMatch(stderr, /`globalPreload` is an experimental feature/);
446-
});
447-
448-
it('should handle globalPreload returning undefined', async () => {
449-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
450-
'--no-warnings',
451-
'--experimental-loader',
452-
'data:text/javascript,export function globalPreload(){}',
453-
fixtures.path('empty.js'),
454-
]);
455-
456-
assert.strictEqual(stderr, '');
457-
assert.strictEqual(stdout, '');
458-
assert.strictEqual(code, 0);
459-
assert.strictEqual(signal, null);
460-
});
461-
462-
it('should handle loading node:test', async () => {
463-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
464-
'--no-warnings',
465-
'--experimental-loader',
466-
'data:text/javascript,export function globalPreload(){return `getBuiltin("node:test")()`}',
467-
fixtures.path('empty.js'),
468-
]);
469-
470-
assert.strictEqual(stderr, '');
471-
assert.match(stdout, /\n# pass 1\r?\n/);
472-
assert.strictEqual(code, 0);
473-
assert.strictEqual(signal, null);
474-
});
475-
476-
it('should handle loading node:os with node: prefix', async () => {
477-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
478-
'--no-warnings',
479-
'--experimental-loader',
480-
'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("node:os").arch())`}',
481-
fixtures.path('empty.js'),
482-
]);
483-
484-
assert.strictEqual(stderr, '');
485-
assert.strictEqual(stdout.trim(), os.arch());
486-
assert.strictEqual(code, 0);
487-
assert.strictEqual(signal, null);
488-
});
489-
490-
// `os` is used here because it's simple and not mocked (the builtin module otherwise doesn't matter).
491-
it('should handle loading builtin module without node: prefix', async () => {
492-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
493-
'--no-warnings',
494-
'--experimental-loader',
495-
'data:text/javascript,export function globalPreload(){return `console.log(getBuiltin("os").arch())`}',
496-
fixtures.path('empty.js'),
497-
]);
498-
499-
assert.strictEqual(stderr, '');
500-
assert.strictEqual(stdout.trim(), os.arch());
501-
assert.strictEqual(code, 0);
502-
assert.strictEqual(signal, null);
503-
});
504-
505-
it('should throw when loading node:test without node: prefix', async () => {
506-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
507-
'--no-warnings',
508-
'--experimental-loader',
509-
'data:text/javascript,export function globalPreload(){return `getBuiltin("test")()`}',
510-
fixtures.path('empty.js'),
511-
]);
512-
513-
assert.match(stderr, /ERR_UNKNOWN_BUILTIN_MODULE/);
514-
assert.strictEqual(stdout, '');
515-
assert.strictEqual(code, 1);
516-
assert.strictEqual(signal, null);
517-
});
518-
519-
it('should register globals set from globalPreload', async () => {
520-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
521-
'--no-warnings',
522-
'--experimental-loader',
523-
'data:text/javascript,export function globalPreload(){return "this.myGlobal=4"}',
524-
'--print', 'myGlobal',
525-
]);
526-
527-
assert.strictEqual(stderr, '');
528-
assert.strictEqual(stdout.trim(), '4');
529-
assert.strictEqual(code, 0);
530-
assert.strictEqual(signal, null);
531-
});
532-
533-
it('should log console.log calls returned from globalPreload', async () => {
534-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
535-
'--no-warnings',
536-
'--experimental-loader',
537-
'data:text/javascript,export function globalPreload(){return `console.log("Hello from globalPreload")`}',
538-
fixtures.path('empty.js'),
539-
]);
540-
541-
assert.strictEqual(stderr, '');
542-
assert.strictEqual(stdout.trim(), 'Hello from globalPreload');
543-
assert.strictEqual(code, 0);
544-
assert.strictEqual(signal, null);
545-
});
546-
547-
it('should crash if globalPreload returns code that throws', async () => {
548-
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
549-
'--no-warnings',
550-
'--experimental-loader',
551-
'data:text/javascript,export function globalPreload(){return `throw new Error("error from globalPreload")`}',
552-
fixtures.path('empty.js'),
553-
]);
554-
555-
assert.match(stderr, /error from globalPreload/);
556-
assert.strictEqual(stdout, '');
557-
assert.strictEqual(code, 1);
558-
assert.strictEqual(signal, null);
559-
});
560-
});
561-
562425
it('should be fine to call `process.removeAllListeners("beforeExit")` from the main thread', async () => {
563426
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
564427
'--no-warnings',
@@ -630,7 +493,7 @@ describe('Loader hooks', { concurrency: true }, () => {
630493
assert.strictEqual(signal, null);
631494
});
632495

633-
it('should have `register` work with cjs', async () => {
496+
it('should `register` from cjs', async () => {
634497
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
635498
'--no-warnings',
636499
'--input-type=commonjs',

test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,6 @@ import { readFileSync } from 'node:fs';
33

44
const GET_BUILTIN = `$__get_builtin_hole_${Date.now()}`;
55

6-
export function globalPreload() {
7-
return `Object.defineProperty(globalThis, ${JSON.stringify(GET_BUILTIN)}, {
8-
value: (builtinName) => {
9-
return getBuiltin(builtinName);
10-
},
11-
enumerable: false,
12-
configurable: false,
13-
});
14-
`;
15-
}
16-
176
export async function resolve(specifier, context, next) {
187
const def = await next(specifier, context);
198

@@ -56,7 +45,7 @@ const $builtinInstance = ${GET_BUILTIN}(${JSON.stringify(builtinName)});
5645
module.exports = $builtinInstance;
5746
module.exports.__fromLoader = true;
5847
59-
// We need this for CJS-module-lexer can parse the exported names.
48+
// We need this for CJS-module-lexer can parse the exported names.
6049
${
6150
builtinExports
6251
.map(name => `exports.${name} = $builtinInstance.${name};`)

test/fixtures/es-module-loaders/hook-resolve-type.mjs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,6 @@
11
let importedESM = 0;
22
let importedCJS = 0;
33

4-
export function globalPreload({ port }) {
5-
port.on('message', (int32) => {
6-
port.postMessage({ importedESM, importedCJS });
7-
Atomics.store(int32, 0, 1);
8-
Atomics.notify(int32, 0);
9-
});
10-
port.unref();
11-
return `
12-
const { receiveMessageOnPort } = getBuiltin('worker_threads');
13-
global.getModuleTypeStats = async function getModuleTypeStats() {
14-
const sab = new SharedArrayBuffer(4);
15-
const int32 = new Int32Array(sab);
16-
port.postMessage(int32);
17-
// Artificial timeout to keep the event loop alive.
18-
// https://bugs.chromium.org/p/v8/issues/detail?id=13238
19-
// TODO(targos) Remove when V8 issue is resolved.
20-
const timeout = setTimeout(() => { throw new Error('timeout'); }, 1_000);
21-
await Atomics.waitAsync(int32, 0, 0).value;
22-
clearTimeout(timeout);
23-
return receiveMessageOnPort(port).message;
24-
};
25-
`;
26-
}
27-
284
export async function load(url, context, next) {
295
return next(url);
306
}

test/fixtures/es-module-loaders/loader-side-effect.mjs

Lines changed: 0 additions & 32 deletions
This file was deleted.

test/fixtures/es-module-loaders/loader-this-value-inside-hook-functions.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function load(url, _, next) {
88
return next(url);
99
}
1010

11-
export function globalPreload() {
11+
export function initialize() {
1212
if (this != null) throw new Error('hook function must not be bound to ESMLoader instance');
1313
return "";
1414
}

0 commit comments

Comments
 (0)