@@ -50,7 +50,6 @@ const {
50
50
ReflectSet,
51
51
RegExpPrototypeExec,
52
52
SafeMap,
53
- SafeWeakMap,
54
53
String,
55
54
StringPrototypeCharAt,
56
55
StringPrototypeCharCodeAt,
@@ -62,25 +61,50 @@ const {
62
61
StringPrototypeStartsWith,
63
62
Symbol,
64
63
} = primordials ;
64
+ const {
65
+ privateSymbols : {
66
+ module_source_private_symbol,
67
+ module_export_names_private_symbol,
68
+ module_circular_visited_private_symbol,
69
+ module_export_private_symbol,
70
+ module_parent_private_symbol,
71
+ } ,
72
+ } = internalBinding ( 'util' ) ;
65
73
66
74
const { kEvaluated } = internalBinding ( 'module_wrap' ) ;
67
75
68
- // Map used to store CJS parsing data or for ESM loading.
69
- const importedCJSCache = new SafeWeakMap ( ) ;
76
+ // Internal properties for Module instances.
77
+ /**
78
+ * Cached {@link Module} source string.
79
+ */
80
+ const kModuleSource = module_source_private_symbol ;
81
+ /**
82
+ * Cached {@link Module} export names for ESM loader.
83
+ */
84
+ const kModuleExportNames = module_export_names_private_symbol ;
85
+ /**
86
+ * {@link Module } circular dependency visited flag.
87
+ */
88
+ const kModuleCircularVisited = module_circular_visited_private_symbol ;
70
89
/**
71
- * Map of already-loaded CJS modules to use .
90
+ * { @link Module } export object snapshot for ESM loader .
72
91
*/
73
- const cjsExportsCache = new SafeWeakMap ( ) ;
74
- const requiredESMSourceCache = new SafeWeakMap ( ) ;
92
+ const kModuleExport = module_export_private_symbol ;
93
+ /**
94
+ * {@link Module } parent module.
95
+ */
96
+ const kModuleParent = module_parent_private_symbol ;
75
97
76
98
const kIsMainSymbol = Symbol ( 'kIsMainSymbol' ) ;
77
99
const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
78
100
const kRequiredModuleSymbol = Symbol ( 'kRequiredModuleSymbol' ) ;
79
101
const kIsExecuting = Symbol ( 'kIsExecuting' ) ;
80
102
// Set first due to cycle with ESM loader functions.
81
103
module . exports = {
82
- cjsExportsCache,
83
- importedCJSCache,
104
+ kModuleSource,
105
+ kModuleExport,
106
+ kModuleExportNames,
107
+ kModuleCircularVisited,
84
108
initializeCJS,
85
109
entryPointSource : undefined , // Set below.
86
110
Module,
@@ -257,8 +281,6 @@ function reportModuleNotFoundToWatchMode(basePath, extensions) {
257
281
}
258
282
}
259
283
260
- /** @type {Map<Module, Module> } */
261
- const moduleParentCache = new SafeWeakMap ( ) ;
262
284
/**
263
285
* Create a new module instance.
264
286
* @param {string } id
@@ -268,7 +290,7 @@ function Module(id = '', parent) {
268
290
this . id = id ;
269
291
this . path = path . dirname ( id ) ;
270
292
setOwnProperty ( this , 'exports' , { } ) ;
271
- moduleParentCache . set ( this , parent ) ;
293
+ this [ kModuleParent ] = parent ;
272
294
updateChildren ( parent , this , false ) ;
273
295
this . filename = null ;
274
296
this . loaded = false ;
@@ -356,17 +378,19 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
356
378
357
379
/**
358
380
* Get the parent of the current module from our cache.
381
+ * @this {Module}
359
382
*/
360
383
function getModuleParent ( ) {
361
- return moduleParentCache . get ( this ) ;
384
+ return this [ kModuleParent ] ;
362
385
}
363
386
364
387
/**
365
388
* Set the parent of the current module in our cache.
389
+ * @this {Module}
366
390
* @param {Module } value
367
391
*/
368
392
function setModuleParent ( value ) {
369
- moduleParentCache . set ( this , value ) ;
393
+ this [ kModuleParent ] = value ;
370
394
}
371
395
372
396
let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'module' , ( fn ) => {
@@ -955,7 +979,7 @@ function getExportsForCircularRequire(module) {
955
979
const requiredESM = module [ kRequiredModuleSymbol ] ;
956
980
if ( requiredESM && requiredESM . getStatus ( ) !== kEvaluated ) {
957
981
let message = `Cannot require() ES Module ${ module . id } in a cycle.` ;
958
- const parent = moduleParentCache . get ( module ) ;
982
+ const parent = module [ kModuleParent ] ;
959
983
if ( parent ) {
960
984
message += ` (from ${ parent . filename } )` ;
961
985
}
@@ -1028,25 +1052,24 @@ Module._load = function(request, parent, isMain) {
1028
1052
const cachedModule = Module . _cache [ filename ] ;
1029
1053
if ( cachedModule !== undefined ) {
1030
1054
updateChildren ( parent , cachedModule , true ) ;
1031
- if ( ! cachedModule . loaded ) {
1032
- // If it's not cached by the ESM loader, the loading request
1033
- // comes from required CJS, and we can consider it a circular
1034
- // dependency when it's cached.
1035
- if ( ! cachedModule [ kIsCachedByESMLoader ] ) {
1036
- return getExportsForCircularRequire ( cachedModule ) ;
1037
- }
1038
- // If it's cached by the ESM loader as a way to indirectly pass
1039
- // the module in to avoid creating it twice, the loading request
1040
- // come from imported CJS. In that case use the importedCJSCache
1041
- // to determine if it's loading or not.
1042
- const importedCJSMetadata = importedCJSCache . get ( cachedModule ) ;
1043
- if ( importedCJSMetadata . loading ) {
1044
- return getExportsForCircularRequire ( cachedModule ) ;
1045
- }
1046
- importedCJSMetadata . loading = true ;
1047
- } else {
1055
+ if ( cachedModule . loaded ) {
1048
1056
return cachedModule . exports ;
1049
1057
}
1058
+ // If it's not cached by the ESM loader, the loading request
1059
+ // comes from required CJS, and we can consider it a circular
1060
+ // dependency when it's cached.
1061
+ if ( ! cachedModule [ kIsCachedByESMLoader ] ) {
1062
+ return getExportsForCircularRequire ( cachedModule ) ;
1063
+ }
1064
+ // If it's cached by the ESM loader as a way to indirectly pass
1065
+ // the module in to avoid creating it twice, the loading request
1066
+ // come from imported CJS. In that case use the kModuleCircularVisited
1067
+ // to determine if it's loading or not.
1068
+ if ( cachedModule [ kModuleCircularVisited ] ) {
1069
+ return getExportsForCircularRequire ( cachedModule ) ;
1070
+ }
1071
+ // This is an ESM loader created cache entry, mark it as visited and fallthrough to loading the module.
1072
+ cachedModule [ kModuleCircularVisited ] = true ;
1050
1073
}
1051
1074
1052
1075
if ( BuiltinModule . canBeRequiredWithoutScheme ( filename ) ) {
@@ -1190,7 +1213,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
1190
1213
const requireStack = [ ] ;
1191
1214
for ( let cursor = parent ;
1192
1215
cursor ;
1193
- cursor = moduleParentCache . get ( cursor ) ) {
1216
+ cursor = cursor [ kModuleParent ] ) {
1194
1217
ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
1195
1218
}
1196
1219
let message = `Cannot find module '${ request } '` ;
@@ -1268,9 +1291,7 @@ Module.prototype.load = function(filename) {
1268
1291
// Create module entry at load time to snapshot exports correctly
1269
1292
const exports = this . exports ;
1270
1293
// Preemptively cache for ESM loader.
1271
- if ( ! cjsExportsCache . has ( this ) ) {
1272
- cjsExportsCache . set ( this , exports ) ;
1273
- }
1294
+ this [ kModuleExport ] = exports ;
1274
1295
} ;
1275
1296
1276
1297
/**
@@ -1313,7 +1334,7 @@ function loadESMFromCJS(mod, filename) {
1313
1334
const isMain = mod [ kIsMainSymbol ] ;
1314
1335
// TODO(joyeecheung): we may want to invent optional special handling for default exports here.
1315
1336
// For now, it's good enough to be identical to what `import()` returns.
1316
- mod . exports = cascadedLoader . importSyncForRequire ( mod , filename , source , isMain , moduleParentCache . get ( mod ) ) ;
1337
+ mod . exports = cascadedLoader . importSyncForRequire ( mod , filename , source , isMain , mod [ kModuleParent ] ) ;
1317
1338
}
1318
1339
1319
1340
/**
@@ -1406,7 +1427,7 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1406
1427
// Only modules being require()'d really need to avoid TLA.
1407
1428
if ( loadAsESM ) {
1408
1429
// Pass the source into the .mjs extension handler indirectly through the cache.
1409
- requiredESMSourceCache . set ( this , content ) ;
1430
+ this [ kModuleSource ] = content ;
1410
1431
loadESMFromCJS ( this , filename ) ;
1411
1432
return ;
1412
1433
}
@@ -1467,15 +1488,15 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1467
1488
* @returns {string }
1468
1489
*/
1469
1490
function getMaybeCachedSource ( mod , filename ) {
1470
- const cached = importedCJSCache . get ( mod ) ;
1491
+ // If already analyzed the source, then it will be cached.
1471
1492
let content ;
1472
- if ( cached ?. source ) {
1473
- content = cached . source ;
1474
- cached . source = undefined ;
1493
+ if ( mod [ kModuleSource ] !== undefined ) {
1494
+ content = mod [ kModuleSource ] ;
1495
+ mod [ kModuleSource ] = undefined ;
1475
1496
} else {
1476
1497
// TODO(joyeecheung): we can read a buffer instead to speed up
1477
1498
// compilation.
1478
- content = requiredESMSourceCache . get ( mod ) ?? fs . readFileSync ( filename , 'utf8' ) ;
1499
+ content = fs . readFileSync ( filename , 'utf8' ) ;
1479
1500
}
1480
1501
return content ;
1481
1502
}
@@ -1499,7 +1520,7 @@ Module._extensions['.js'] = function(module, filename) {
1499
1520
}
1500
1521
1501
1522
// This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1502
- const parent = moduleParentCache . get ( module ) ;
1523
+ const parent = module [ kModuleParent ] ;
1503
1524
const parentPath = parent ?. filename ;
1504
1525
const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
1505
1526
const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments