@@ -19,6 +19,7 @@ const {
19
19
SafeWeakMap,
20
20
globalThis,
21
21
} = primordials ;
22
+ const { MessageChannel } = require ( 'internal/worker/io' ) ;
22
23
23
24
const {
24
25
ERR_INVALID_ARG_TYPE ,
@@ -40,6 +41,9 @@ const {
40
41
defaultResolve,
41
42
DEFAULT_CONDITIONS ,
42
43
} = require ( 'internal/modules/esm/resolve' ) ;
44
+ const {
45
+ initializeImportMeta
46
+ } = require ( 'internal/modules/esm/initialize_import_meta' ) ;
43
47
const { defaultLoad } = require ( 'internal/modules/esm/load' ) ;
44
48
const { translators } = require (
45
49
'internal/modules/esm/translators' ) ;
@@ -77,6 +81,8 @@ class ESMLoader {
77
81
defaultResolve ,
78
82
] ;
79
83
84
+ #importMetaInitializer = initializeImportMeta ;
85
+
80
86
/**
81
87
* Map of already-loaded CJS modules to use
82
88
*/
@@ -409,7 +415,18 @@ class ESMLoader {
409
415
if ( ! count ) return ;
410
416
411
417
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
+ } ) ;
413
430
414
431
if ( preload == null ) return ;
415
432
@@ -423,22 +440,60 @@ class ESMLoader {
423
440
const { compileFunction } = require ( 'vm' ) ;
424
441
const preloadInit = compileFunction (
425
442
preload ,
426
- [ 'getBuiltin' ] ,
443
+ [ 'getBuiltin' , 'port' , 'setImportMetaCallback' ] ,
427
444
{
428
445
filename : '<preload>' ,
429
446
}
430
447
) ;
431
448
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 ;
436
488
}
437
- throw new ERR_INVALID_ARG_VALUE ( 'builtinName' , builtinName ) ;
438
- } ) ;
489
+ }
439
490
}
440
491
}
441
492
493
+ importMetaInitialize ( meta , context ) {
494
+ this . #importMetaInitializer( meta , context ) ;
495
+ }
496
+
442
497
/**
443
498
* Resolve the location of the module.
444
499
*
0 commit comments