Skip to content

Commit 28d6893

Browse files
committed
module: initialize hook returns load, resolve
This commit allows the `initialize()` hook to optionally return an object having the `resolve()` and `load()` hooks as properties. This allows state passed into `initialize()` to be shared with the `resolve()` and `load()` hooks either via closure or class instance. In addition to developer ergonomics, supporting this model will make it easier to write tests against a loader module. The existing design forces state to be shared at the module level which puts the burden of invalidating the ESM module cache on anyone hoping to write isolated tests against a loader module. Fixes: #50042
1 parent 609b13e commit 28d6893

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

lib/internal/modules/esm/hooks.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const {
44
ArrayPrototypePush,
55
ArrayPrototypePushApply,
6+
FunctionPrototypeBind,
67
Int32Array,
78
ObjectAssign,
89
ObjectDefineProperty,
@@ -139,7 +140,7 @@ class Hooks {
139140
* to the worker.
140141
* @returns {any | Promise<any>} User data, ignored unless it's a promise, in which case it will be awaited.
141142
*/
142-
addCustomLoader(url, exports, data) {
143+
async addCustomLoader(url, exports, data) {
143144
const {
144145
initialize,
145146
resolve,
@@ -154,7 +155,30 @@ class Hooks {
154155
const next = this.#chains.load[this.#chains.load.length - 1];
155156
ArrayPrototypePush(this.#chains.load, { __proto__: null, fn: load, url, next });
156157
}
157-
return initialize?.(data);
158+
159+
const hooks = await initialize?.(data);
160+
161+
if (hooks?.resolve) {
162+
if (resolve) {
163+
throw new ERR_INTERNAL_ASSERTION(
164+
`ESM custom loader '${url}' exposed a 'resolve' hook and returned an object with a 'resolve' hook.`,
165+
);
166+
}
167+
const next = this.#chains.resolve[this.#chains.resolve.length - 1];
168+
const boundResolve = FunctionPrototypeBind(hooks.resolve, hooks);
169+
ArrayPrototypePush(this.#chains.resolve, { __proto__: null, fn: boundResolve, url, next });
170+
}
171+
172+
if (hooks?.load) {
173+
if (load) {
174+
throw new ERR_INTERNAL_ASSERTION(
175+
`ESM custom loader '${url}' exposed a 'load' hook and returned an object with a 'load' hook.`,
176+
);
177+
}
178+
const next = this.#chains.load[this.#chains.load.length - 1];
179+
const boundLoad = FunctionPrototypeBind(hooks.load, hooks);
180+
ArrayPrototypePush(this.#chains.load, { __proto__: null, fn: boundLoad, url, next });
181+
}
158182
}
159183

160184
/**

0 commit comments

Comments
 (0)