Skip to content

Commit

Permalink
module: initialize hook returns load, resolve
Browse files Browse the repository at this point in the history
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: nodejs#50042
  • Loading branch information
ggoodman committed Oct 4, 2023
1 parent 609b13e commit 565a5e3
Showing 1 changed file with 22 additions and 2 deletions.
24 changes: 22 additions & 2 deletions lib/internal/modules/esm/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const {
ArrayPrototypePush,
ArrayPrototypePushApply,
FunctionPrototypeBind,
Int32Array,
ObjectAssign,
ObjectDefineProperty,
Expand Down Expand Up @@ -139,7 +140,7 @@ class Hooks {
* to the worker.
* @returns {any | Promise<any>} User data, ignored unless it's a promise, in which case it will be awaited.
*/
addCustomLoader(url, exports, data) {
async addCustomLoader(url, exports, data) {
const {
initialize,
resolve,
Expand All @@ -154,7 +155,26 @@ class Hooks {
const next = this.#chains.load[this.#chains.load.length - 1];
ArrayPrototypePush(this.#chains.load, { __proto__: null, fn: load, url, next });
}
return initialize?.(data);

const hooks = await initialize?.(data);

if (hooks?.resolve) {
if (resolve) {
throw new Error('Invariant violation: both a module-level and returned resolve hook found');
}
const next = this.#chains.resolve[this.#chains.resolve.length - 1];
const boundResolve = FunctionPrototypeBind(hooks.resolve, hooks);
ArrayPrototypePush(this.#chains.resolve, { __proto__: null, fn: boundResolve, url, next });
}

if (hooks?.load) {
if (load) {
throw new Error('Invariant violation: both a module-level and returned load hook found');
}
const next = this.#chains.load[this.#chains.load.length - 1];
const boundLoad = FunctionPrototypeBind(hooks.load, hooks);
ArrayPrototypePush(this.#chains.load, { __proto__: null, fn: boundLoad, url, next });
}
}

/**
Expand Down

0 comments on commit 565a5e3

Please sign in to comment.