@@ -19,6 +19,7 @@ const {
1919 SafeWeakMap,
2020 globalThis,
2121} = primordials ;
22+ const { MessageChannel } = require ( 'internal/worker/io' ) ;
2223
2324const {
2425 ERR_INVALID_ARG_TYPE ,
@@ -40,6 +41,9 @@ const {
4041 defaultResolve,
4142 DEFAULT_CONDITIONS ,
4243} = require ( 'internal/modules/esm/resolve' ) ;
44+ const {
45+ initializeImportMeta
46+ } = require ( 'internal/modules/esm/initialize_import_meta' ) ;
4347const { defaultLoad } = require ( 'internal/modules/esm/load' ) ;
4448const { translators } = require (
4549 'internal/modules/esm/translators' ) ;
@@ -77,6 +81,8 @@ class ESMLoader {
7781 defaultResolve ,
7882 ] ;
7983
84+ #importMetaInitializer = initializeImportMeta ;
85+
8086 /**
8187 * Map of already-loaded CJS modules to use
8288 */
@@ -409,7 +415,18 @@ class ESMLoader {
409415 if ( ! count ) return ;
410416
411417 for ( let i = 0 ; i < count ; i ++ ) {
412- const preload = this . #globalPreloaders[ i ] ( ) ;
418+ const channel = new MessageChannel ( ) ;
419+ const {
420+ port1 : insidePreload ,
421+ port2 : insideLoader ,
422+ } = channel ;
423+
424+ insidePreload . unref ( ) ;
425+ insideLoader . unref ( ) ;
426+
427+ const preload = this . #globalPreloaders[ i ] ( {
428+ port : insideLoader
429+ } ) ;
413430
414431 if ( preload == null ) return ;
415432
@@ -423,22 +440,60 @@ class ESMLoader {
423440 const { compileFunction } = require ( 'vm' ) ;
424441 const preloadInit = compileFunction (
425442 preload ,
426- [ 'getBuiltin' ] ,
443+ [ 'getBuiltin' , 'port' , 'setImportMetaCallback' ] ,
427444 {
428445 filename : '<preload>' ,
429446 }
430447 ) ;
431448 const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
432-
433- FunctionPrototypeCall ( preloadInit , globalThis , ( builtinName ) => {
434- if ( NativeModule . canBeRequiredByUsers ( builtinName ) ) {
435- return require ( builtinName ) ;
449+ // We only allow replacing the importMetaInitializer during preload,
450+ // after preload is finished, we disable the ability to replace it
451+ //
452+ // This exposes accidentally setting the initializer too late by
453+ // throwing an error.
454+ let finished = false ;
455+ let replacedImportMetaInitializer = false ;
456+ let next = this . #importMetaInitializer;
457+ try {
458+ // Calls the compiled preload source text gotten from the hook
459+ // Since the parameters are named we use positional parameters
460+ // see compileFunction above to cross reference the names
461+ FunctionPrototypeCall (
462+ preloadInit ,
463+ globalThis ,
464+ // Param getBuiltin
465+ ( builtinName ) => {
466+ if ( NativeModule . canBeRequiredByUsers ( builtinName ) ) {
467+ return require ( builtinName ) ;
468+ }
469+ throw new ERR_INVALID_ARG_VALUE ( 'builtinName' , builtinName ) ;
470+ } ,
471+ // Param port
472+ insidePreload ,
473+ // Param setImportMetaCallback
474+ ( fn ) => {
475+ if ( finished || typeof fn !== 'function' ) {
476+ throw new ERR_INVALID_ARG_TYPE ( 'fn' , fn ) ;
477+ }
478+ replacedImportMetaInitializer = true ;
479+ const parent = next ;
480+ next = ( meta , context ) => {
481+ return fn ( meta , context , parent ) ;
482+ } ;
483+ } ) ;
484+ } finally {
485+ finished = true ;
486+ if ( replacedImportMetaInitializer ) {
487+ this . #importMetaInitializer = next ;
436488 }
437- throw new ERR_INVALID_ARG_VALUE ( 'builtinName' , builtinName ) ;
438- } ) ;
489+ }
439490 }
440491 }
441492
493+ importMetaInitialize ( meta , context ) {
494+ this . #importMetaInitializer( meta , context ) ;
495+ }
496+
442497 /**
443498 * Resolve the location of the module.
444499 *
0 commit comments