@@ -54,7 +54,6 @@ const {
54
54
} = require ( 'internal/util' ) ;
55
55
56
56
const {
57
- defaultResolve,
58
57
throwIfInvalidParentURL,
59
58
} = require ( 'internal/modules/esm/resolve' ) ;
60
59
const {
@@ -87,45 +86,40 @@ let importMetaInitializer;
87
86
// [2] `validate...()`s throw the wrong error
88
87
89
88
class Hooks {
90
- #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
-
98
- /**
99
- * Phase 1 of 2 in ESM loading.
100
- * The output of the `resolve` chain of hooks is passed into the `load` chain of hooks.
101
- * @private
102
- * @property {KeyedHook[] } resolve Last-in-first-out collection of resolve hooks.
103
- */
104
- resolve : [
105
- {
106
- fn : defaultResolve ,
107
- url : 'node:internal/modules/esm/resolve' ,
108
- } ,
109
- ] ,
110
-
111
- /**
112
- * Phase 2 of 2 in ESM loading.
113
- * @private
114
- * @property {KeyedHook[] } load Last-in-first-out collection of loader hooks.
115
- */
116
- load : [
117
- {
118
- fn : require ( 'internal/modules/esm/load' ) . defaultLoad ,
119
- url : 'node:internal/modules/esm/load' ,
120
- } ,
121
- ] ,
122
- } ;
89
+ #loaderInstances = [ ] ;
90
+ #chains = { } ;
123
91
124
92
// Cache URLs we've already validated to avoid repeated validation
125
93
#validatedUrls = new SafeSet ( ) ;
126
94
127
95
allowImportMetaResolve = false ;
128
96
97
+ constructor ( ) {
98
+ const defaultLoader = 'internal/modules/esm/default_loader' ;
99
+ this . addCustomLoader ( `node:${ defaultLoader } ` , require ( defaultLoader ) ) ;
100
+ }
101
+
102
+ #rebuildChain( name ) {
103
+ const chain = this . #chains[ name ] = [ ] ;
104
+ let i = 0 ;
105
+ for ( const instance of this . #loaderInstances) {
106
+ if ( typeof instance [ name ] !== 'function' ) {
107
+ continue ;
108
+ }
109
+ chain . push ( {
110
+ loader : instance ,
111
+ fn : instance [ name ] ,
112
+ next : chain [ i ++ - 1 ] ,
113
+ } ) ;
114
+ }
115
+ }
116
+
117
+ #rebuildChains( ) {
118
+ this . #rebuildChain( 'globalPreload' ) ;
119
+ this . #rebuildChain( 'resolve' ) ;
120
+ this . #rebuildChain( 'load' ) ;
121
+ }
122
+
129
123
/**
130
124
* Import and register custom/user-defined module loader hook(s).
131
125
* @param {string } urlOrSpecifier
@@ -164,25 +158,26 @@ class Hooks {
164
158
emitExperimentalWarning (
165
159
'`globalPreload` is planned for removal in favor of `initialize`. `globalPreload`' ,
166
160
) ;
167
- ArrayPrototypePush ( this . #chains. globalPreload , { __proto__ : null , fn : globalPreload , url } ) ;
168
- }
169
- if ( resolve ) {
170
- const next = this . #chains. resolve [ this . #chains. resolve . length - 1 ] ;
171
- ArrayPrototypePush ( this . #chains. resolve , { __proto__ : null , fn : resolve , url, next } ) ;
172
161
}
173
- if ( load ) {
174
- const next = this . #chains. load [ this . #chains. load . length - 1 ] ;
175
- ArrayPrototypePush ( this . #chains. load , { __proto__ : null , fn : load , url, next } ) ;
176
- }
177
- return initialize ?. ( data ) ;
162
+ const instance = {
163
+ __proto__ : null ,
164
+ url,
165
+ globalPreload,
166
+ initialize,
167
+ resolve,
168
+ load,
169
+ } ;
170
+ ArrayPrototypePush ( this . #loaderInstances, instance ) ;
171
+ this . #rebuildChains( ) ;
172
+ return initialize ?. ( data , { __proto__ : null , id : instance . id , url } ) ;
178
173
}
179
174
180
175
/**
181
176
* Initialize `globalPreload` hooks.
182
177
*/
183
178
initializeGlobalPreload ( ) {
184
179
const preloadScripts = [ ] ;
185
- for ( let i = this . #chains. globalPreload . length - 1 ; i >= 0 ; i -- ) {
180
+ for ( const chainEntry of this . #chains. globalPreload ) {
186
181
const { MessageChannel } = require ( 'internal/worker/io' ) ;
187
182
const channel = new MessageChannel ( ) ;
188
183
const {
@@ -193,10 +188,7 @@ class Hooks {
193
188
insidePreload . unref ( ) ;
194
189
insideLoader . unref ( ) ;
195
190
196
- const {
197
- fn : preload ,
198
- url : specifier ,
199
- } = this . #chains. globalPreload [ i ] ;
191
+ const preload = chainEntry . fn ;
200
192
201
193
const preloaded = preload ( {
202
194
port : insideLoader ,
@@ -207,8 +199,8 @@ class Hooks {
207
199
if ( typeof preloaded !== 'string' ) { // [2]
208
200
throw new ERR_INVALID_RETURN_VALUE (
209
201
'a string' ,
210
- `${ specifier } globalPreload` ,
211
- preload ,
202
+ `${ chainEntry . loader . url } globalPreload` ,
203
+ chainEntry . fn ,
212
204
) ;
213
205
}
214
206
@@ -240,7 +232,6 @@ class Hooks {
240
232
) {
241
233
throwIfInvalidParentURL ( parentURL ) ;
242
234
243
- const chain = this . #chains. resolve ;
244
235
const context = {
245
236
conditions : getDefaultConditions ( ) ,
246
237
importAssertions,
@@ -272,7 +263,11 @@ class Hooks {
272
263
}
273
264
} ;
274
265
275
- const nextResolve = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
266
+ const nextResolve = nextHookFactory (
267
+ this . #chains. resolve [ this . #chains. resolve . length - 1 ] ,
268
+ meta ,
269
+ { validateArgs, validateOutput } ,
270
+ ) ;
276
271
277
272
const resolution = await nextResolve ( originalSpecifier , context ) ;
278
273
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -364,7 +359,6 @@ class Hooks {
364
359
* @returns {Promise<{ format: ModuleFormat, source: ModuleSource }> }
365
360
*/
366
361
async load ( url , context = { } ) {
367
- const chain = this . #chains. load ;
368
362
const meta = {
369
363
chainFinished : null ,
370
364
context,
@@ -410,7 +404,11 @@ class Hooks {
410
404
}
411
405
} ;
412
406
413
- const nextLoad = nextHookFactory ( chain [ chain . length - 1 ] , meta , { validateArgs, validateOutput } ) ;
407
+ const nextLoad = nextHookFactory (
408
+ this . #chains. load [ this . #chains. load . length - 1 ] ,
409
+ meta ,
410
+ { validateArgs, validateOutput } ,
411
+ ) ;
414
412
415
413
const loaded = await nextLoad ( url , context ) ;
416
414
const { hookErrIdentifier } = meta ; // Retrieve the value after all settled
@@ -789,11 +787,9 @@ function pluckHooks({
789
787
function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
790
788
// First, prepare the current
791
789
const { hookName } = meta ;
792
- const {
793
- fn : hook ,
794
- url : hookFilePath ,
795
- next,
796
- } = current ;
790
+
791
+ const { next, fn : hook , loader } = current ;
792
+ const { url : hookFilePath } = loader ;
797
793
798
794
// ex 'nextResolve'
799
795
const nextHookName = `next${
0 commit comments