@@ -18,6 +18,7 @@ const {
18
18
SafeWeakMap,
19
19
globalThis,
20
20
} = primordials ;
21
+ const { MessageChannel } = require ( 'internal/worker/io' ) ;
21
22
22
23
const {
23
24
ERR_INVALID_ARG_TYPE ,
@@ -39,6 +40,9 @@ const {
39
40
defaultResolve,
40
41
DEFAULT_CONDITIONS ,
41
42
} = require ( 'internal/modules/esm/resolve' ) ;
43
+ const {
44
+ initializeImportMeta
45
+ } = require ( 'internal/modules/esm/initialize_import_meta' ) ;
42
46
const { defaultLoad } = require ( 'internal/modules/esm/load' ) ;
43
47
const { translators } = require (
44
48
'internal/modules/esm/translators' ) ;
@@ -76,6 +80,8 @@ class ESMLoader {
76
80
defaultResolve ,
77
81
] ;
78
82
83
+ #importMetaInitializer = initializeImportMeta ;
84
+
79
85
/**
80
86
* Map of already-loaded CJS modules to use
81
87
*/
@@ -359,7 +365,18 @@ class ESMLoader {
359
365
if ( ! count ) return ;
360
366
361
367
for ( let i = 0 ; i < count ; i ++ ) {
362
- const preload = this . #globalPreloaders[ i ] ( ) ;
368
+ const channel = new MessageChannel ( ) ;
369
+ const {
370
+ port1 : insidePreload ,
371
+ port2 : insideLoader ,
372
+ } = channel ;
373
+
374
+ insidePreload . unref ( ) ;
375
+ insideLoader . unref ( ) ;
376
+
377
+ const preload = this . #globalPreloaders[ i ] ( {
378
+ port : insideLoader
379
+ } ) ;
363
380
364
381
if ( preload == null ) return ;
365
382
@@ -373,22 +390,60 @@ class ESMLoader {
373
390
const { compileFunction } = require ( 'vm' ) ;
374
391
const preloadInit = compileFunction (
375
392
preload ,
376
- [ 'getBuiltin' ] ,
393
+ [ 'getBuiltin' , 'port' , 'setImportMetaCallback' ] ,
377
394
{
378
395
filename : '<preload>' ,
379
396
}
380
397
) ;
381
398
const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
382
-
383
- FunctionPrototypeCall ( preloadInit , globalThis , ( builtinName ) => {
384
- if ( NativeModule . canBeRequiredByUsers ( builtinName ) ) {
385
- return require ( builtinName ) ;
399
+ // We only allow replacing the importMetaInitializer during preload,
400
+ // after preload is finished, we disable the ability to replace it
401
+ //
402
+ // This exposes accidentally setting the initializer too late by
403
+ // throwing an error.
404
+ let finished = false ;
405
+ let replacedImportMetaInitializer = false ;
406
+ let next = this . #importMetaInitializer;
407
+ try {
408
+ // Calls the compiled preload source text gotten from the hook
409
+ // Since the parameters are named we use positional parameters
410
+ // see compileFunction above to cross reference the names
411
+ FunctionPrototypeCall (
412
+ preloadInit ,
413
+ globalThis ,
414
+ // Param getBuiltin
415
+ ( builtinName ) => {
416
+ if ( NativeModule . canBeRequiredByUsers ( builtinName ) ) {
417
+ return require ( builtinName ) ;
418
+ }
419
+ throw new ERR_INVALID_ARG_VALUE ( 'builtinName' , builtinName ) ;
420
+ } ,
421
+ // Param port
422
+ insidePreload ,
423
+ // Param setImportMetaCallback
424
+ ( fn ) => {
425
+ if ( finished || typeof fn !== 'function' ) {
426
+ throw new ERR_INVALID_ARG_TYPE ( 'fn' , fn ) ;
427
+ }
428
+ replacedImportMetaInitializer = true ;
429
+ const parent = next ;
430
+ next = ( meta , context ) => {
431
+ return fn ( meta , context , parent ) ;
432
+ } ;
433
+ } ) ;
434
+ } finally {
435
+ finished = true ;
436
+ if ( replacedImportMetaInitializer ) {
437
+ this . #importMetaInitializer = next ;
386
438
}
387
- throw new ERR_INVALID_ARG_VALUE ( 'builtinName' , builtinName ) ;
388
- } ) ;
439
+ }
389
440
}
390
441
}
391
442
443
+ importMetaInitialize ( meta , context ) {
444
+ this . #importMetaInitializer( meta , context ) ;
445
+ }
446
+
392
447
/**
393
448
* Resolve the location of the module.
394
449
*
0 commit comments