@@ -54,7 +54,6 @@ const {
5454} = require ( 'internal/util' ) ;
5555
5656const {
57- defaultResolve,
5857 throwIfInvalidParentURL,
5958} = require ( 'internal/modules/esm/resolve' ) ;
6059const {
@@ -87,45 +86,40 @@ let importMetaInitializer;
8786// [2] `validate...()`s throw the wrong error
8887
8988class 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 = { } ;
12391
12492 // Cache URLs we've already validated to avoid repeated validation
12593 #validatedUrls = new SafeSet ( ) ;
12694
12795 allowImportMetaResolve = false ;
12896
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+
129123 /**
130124 * Import and register custom/user-defined module loader hook(s).
131125 * @param {string } urlOrSpecifier
@@ -164,25 +158,26 @@ class Hooks {
164158 emitExperimentalWarning (
165159 '`globalPreload` is planned for removal in favor of `initialize`. `globalPreload`' ,
166160 ) ;
167- ArrayPrototypePush ( this . #chains. globalPreload , { __proto__ : null , fn : globalPreload , url } ) ;
168161 }
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- }
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 } ) ;
178173 }
179174
180175 /**
181176 * Initialize `globalPreload` hooks.
182177 */
183178 initializeGlobalPreload ( ) {
184179 const preloadScripts = [ ] ;
185- for ( let i = this . #chains. globalPreload . length - 1 ; i >= 0 ; i -- ) {
180+ for ( const chainEntry of this . #chains. globalPreload ) {
186181 const { MessageChannel } = require ( 'internal/worker/io' ) ;
187182 const channel = new MessageChannel ( ) ;
188183 const {
@@ -193,10 +188,8 @@ class Hooks {
193188 insidePreload . unref ( ) ;
194189 insideLoader . unref ( ) ;
195190
196- const {
197- fn : preload ,
198- url : specifier ,
199- } = this . #chains. globalPreload [ i ] ;
191+ const preload = chainEntry . fn ;
192+ const specifier = chainEntry . loader . url ;
200193
201194 const preloaded = preload ( {
202195 port : insideLoader ,
@@ -789,11 +782,9 @@ function pluckHooks({
789782function nextHookFactory ( current , meta , { validateArgs, validateOutput } ) {
790783 // First, prepare the current
791784 const { hookName } = meta ;
792- const {
793- fn : hook ,
794- url : hookFilePath ,
795- next,
796- } = current ;
785+
786+ const { next, fn : hook , loader } = current ;
787+ const { url : hookFilePath } = loader ;
797788
798789 // ex 'nextResolve'
799790 const nextHookName = `next${
0 commit comments