@@ -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
Module,
86
110
wrapSafe,
@@ -256,8 +280,6 @@ function reportModuleNotFoundToWatchMode(basePath, extensions) {
256
280
}
257
281
}
258
282
259
- /** @type {Map<Module, Module> } */
260
- const moduleParentCache = new SafeWeakMap ( ) ;
261
283
/**
262
284
* Create a new module instance.
263
285
* @param {string } id
@@ -267,7 +289,7 @@ function Module(id = '', parent) {
267
289
this . id = id ;
268
290
this . path = path . dirname ( id ) ;
269
291
setOwnProperty ( this , 'exports' , { } ) ;
270
- moduleParentCache . set ( this , parent ) ;
292
+ this [ kModuleParent ] = parent ;
271
293
updateChildren ( parent , this , false ) ;
272
294
this . filename = null ;
273
295
this . loaded = false ;
@@ -355,17 +377,19 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
355
377
356
378
/**
357
379
* Get the parent of the current module from our cache.
380
+ * @this {Module}
358
381
*/
359
382
function getModuleParent ( ) {
360
- return moduleParentCache . get ( this ) ;
383
+ return this [ kModuleParent ] ;
361
384
}
362
385
363
386
/**
364
387
* Set the parent of the current module in our cache.
388
+ * @this {Module}
365
389
* @param {Module } value
366
390
*/
367
391
function setModuleParent ( value ) {
368
- moduleParentCache . set ( this , value ) ;
392
+ this [ kModuleParent ] = value ;
369
393
}
370
394
371
395
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
/**
@@ -1399,7 +1420,7 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1399
1420
// Only modules being require()'d really need to avoid TLA.
1400
1421
if ( loadAsESM ) {
1401
1422
// Pass the source into the .mjs extension handler indirectly through the cache.
1402
- requiredESMSourceCache . set ( this , content ) ;
1423
+ this [ kModuleSource ] = content ;
1403
1424
loadESMFromCJS ( this , filename ) ;
1404
1425
return ;
1405
1426
}
@@ -1460,15 +1481,15 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1460
1481
* @returns {string }
1461
1482
*/
1462
1483
function getMaybeCachedSource ( mod , filename ) {
1463
- const cached = importedCJSCache . get ( mod ) ;
1484
+ // If already analyzed the source, then it will be cached.
1464
1485
let content ;
1465
- if ( cached ?. source ) {
1466
- content = cached . source ;
1467
- cached . source = undefined ;
1486
+ if ( mod [ kModuleSource ] !== undefined ) {
1487
+ content = mod [ kModuleSource ] ;
1488
+ mod [ kModuleSource ] = undefined ;
1468
1489
} else {
1469
1490
// TODO(joyeecheung): we can read a buffer instead to speed up
1470
1491
// compilation.
1471
- content = requiredESMSourceCache . get ( mod ) ?? fs . readFileSync ( filename , 'utf8' ) ;
1492
+ content = fs . readFileSync ( filename , 'utf8' ) ;
1472
1493
}
1473
1494
return content ;
1474
1495
}
@@ -1492,7 +1513,7 @@ Module._extensions['.js'] = function(module, filename) {
1492
1513
}
1493
1514
1494
1515
// This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1495
- const parent = moduleParentCache . get ( module ) ;
1516
+ const parent = module [ kModuleParent ] ;
1496
1517
const parentPath = parent ?. filename ;
1497
1518
const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
1498
1519
const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments