Skip to content

Commit 409484a

Browse files
esm: refactor DefaultModuleLoader
Fixes #48515 Fixes #48439
1 parent 951da52 commit 409484a

10 files changed

+278
-157
lines changed
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const { getOptionValue } = require('internal/options');
2+
const assert = require('internal/assert');
3+
4+
const {
5+
ERR_INVALID_ARG_VALUE,
6+
} = require('internal/errors').codes;
7+
8+
const {
9+
ArrayIsArray,
10+
SafeSet,
11+
ObjectFreeze,
12+
} = primordials;
13+
14+
let defaultConditions;
15+
function getDefaultConditions() {
16+
assert(defaultConditions !== undefined);
17+
return defaultConditions;
18+
}
19+
20+
let defaultConditionsSet;
21+
function getDefaultConditionsSet() {
22+
assert(defaultConditionsSet !== undefined);
23+
return defaultConditionsSet;
24+
}
25+
26+
// This function is called during pre-execution, before any user code is run.
27+
function initializeDefaultConditions() {
28+
const userConditions = getOptionValue('--conditions');
29+
const noAddons = getOptionValue('--no-addons');
30+
const addonConditions = noAddons ? [] : ['node-addons'];
31+
32+
defaultConditions = ObjectFreeze([
33+
'node',
34+
'import',
35+
...addonConditions,
36+
...userConditions,
37+
]);
38+
defaultConditionsSet = new SafeSet(defaultConditions);
39+
}
40+
41+
/**
42+
* @param {string[]} [conditions]
43+
* @returns {Set<string>}
44+
*/
45+
function getConditionsSet(conditions) {
46+
if (conditions !== undefined && conditions !== getDefaultConditions()) {
47+
if (!ArrayIsArray(conditions)) {
48+
throw new ERR_INVALID_ARG_VALUE('conditions', conditions,
49+
'expected an array');
50+
}
51+
return new SafeSet(conditions);
52+
}
53+
return getDefaultConditionsSet();
54+
}
55+
56+
module.exports = {
57+
initializeDefaultConditions,
58+
getDefaultConditions,
59+
getConditionsSet,
60+
};

lib/internal/modules/esm/hooks.js

+46-13
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ const {
5151
defaultResolve,
5252
throwIfInvalidParentURL,
5353
} = require('internal/modules/esm/resolve');
54-
const {
55-
getDefaultConditions,
56-
loaderWorkerId,
57-
} = require('internal/modules/esm/utils');
54+
const {loaderWorkerId} = require('internal/modules/esm/utils');
55+
const {getDefaultConditions} = require('internal/modules/esm/conditions');
5856
const { deserializeError } = require('internal/error_serdes');
5957
const {
6058
SHARED_MEMORY_BYTE_LENGTH,
@@ -81,8 +79,8 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
8179
// [2] `validate...()`s throw the wrong error
8280

8381

84-
class Hooks {
85-
#chains = {
82+
function getDefaultChains() {
83+
return {
8684
/**
8785
* Prior to ESM loading. These are called once before any modules are started.
8886
* @private
@@ -115,27 +113,42 @@ class Hooks {
115113
},
116114
],
117115
};
116+
}
117+
118+
class Hooks {
119+
#chains;
118120

119121
// Cache URLs we've already validated to avoid repeated validation
120-
#validatedUrls = new SafeSet();
122+
#validatedUrls;
123+
124+
constructor(chains = getDefaultChains(), validatedUrls = new SafeSet()) {
125+
this.#chains = chains;
126+
this.#validatedUrls = validatedUrls;
127+
}
121128

122129
/**
123130
* Import and register custom/user-defined module loader hook(s).
124131
* @param {string} urlOrSpecifier
125132
* @param {string} parentURL
126133
*/
127134
async register(urlOrSpecifier, parentURL) {
128-
const moduleLoader = require('internal/process/esm_loader').esmLoader;
129-
130-
const keyedExports = await moduleLoader.import(
135+
const esmLoader = require('internal/process/esm_loader').esmLoader;
136+
const keyedExports = await esmLoader.import(
131137
urlOrSpecifier,
132138
parentURL,
133139
kEmptyObject,
134140
);
135-
136141
this.addCustomLoader(urlOrSpecifier, keyedExports);
137142
}
138143

144+
getChains() {
145+
return this.#chains;
146+
}
147+
148+
getValidatedUrls() {
149+
return this.#validatedUrls;
150+
}
151+
139152
/**
140153
* Collect custom/user-defined module loader hook(s).
141154
* After all hooks have been collected, the global preload hook(s) must be initialized.
@@ -221,15 +234,16 @@ class Hooks {
221234
parentURL,
222235
importAssertions = { __proto__: null },
223236
) {
237+
const chain = this.#chains.resolve;
224238
throwIfInvalidParentURL(parentURL);
225239

226-
const chain = this.#chains.resolve;
227240
const context = {
228241
conditions: getDefaultConditions(),
229242
importAssertions,
230243
parentURL,
231244
};
232245
const meta = {
246+
hooks: this,
233247
chainFinished: null,
234248
context,
235249
hookErrIdentifier: '',
@@ -346,6 +360,7 @@ class Hooks {
346360
async load(url, context = {}) {
347361
const chain = this.#chains.load;
348362
const meta = {
363+
hooks: this,
349364
chainFinished: null,
350365
context,
351366
hookErrIdentifier: '',
@@ -749,7 +764,25 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) {
749764
ObjectAssign(meta.context, context);
750765
}
751766

752-
const output = await hook(arg0, meta.context, nextNextHook);
767+
const esmLoader = require('internal/process/esm_loader').esmLoader;
768+
769+
const chains = meta.hooks.getChains();
770+
const load = chain === chains.load ? chains.load.slice(0, generatedHookIndex) : chains.load;
771+
const resolve = chain === chains.resolve ? chains.resolve.slice(0, generatedHookIndex) : chains.resolve;
772+
let output;
773+
if (load.length > 0 && resolve.length > 0) {
774+
const nextChains = {
775+
load,
776+
resolve,
777+
globalPreload: chains.globalPreload,
778+
}
779+
const delegate = new Hooks(nextChains, meta.hooks.getValidatedUrls());
780+
output = await esmLoader.withDelegate(delegate, async () => {
781+
return await hook(arg0, meta.context, nextNextHook);
782+
});
783+
} else {
784+
output = await hook(arg0, meta.context, nextNextHook);
785+
}
753786

754787
validateOutput(outputErrIdentifier, output);
755788

0 commit comments

Comments
 (0)