@@ -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,18 +61,44 @@ 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
- // Map used to store CJS parsing data or for ESM loading.
67
- const cjsSourceCache = new SafeWeakMap ( ) ;
74
+ // Internal properties for Module instances.
68
75
/**
69
- * Map of already-loaded CJS modules to use .
76
+ * Cached { @link Module} source string .
70
77
*/
71
- const cjsExportsCache = new SafeWeakMap ( ) ;
78
+ const kModuleSource = module_source_private_symbol ;
79
+ /**
80
+ * Cached {@link Module} export names for ESM loader.
81
+ */
82
+ const kModuleExportNames = module_export_names_private_symbol ;
83
+ /**
84
+ * {@link Module } circular dependency visited flag.
85
+ */
86
+ const kModuleCircularVisited = module_circular_visited_private_symbol ;
87
+ /**
88
+ * {@link Module } export object snapshot for ESM loader.
89
+ */
90
+ const kModuleExport = module_export_private_symbol ;
91
+ /**
92
+ * {@link Module } parent module.
93
+ */
94
+ const kModuleParent = module_parent_private_symbol ;
72
95
73
96
// Set first due to cycle with ESM loader functions.
74
97
module . exports = {
75
- cjsExportsCache,
76
- cjsSourceCache,
98
+ kModuleSource,
99
+ kModuleExport,
100
+ kModuleExportNames,
101
+ kModuleCircularVisited,
77
102
initializeCJS,
78
103
Module,
79
104
wrapSafe,
@@ -246,8 +271,6 @@ function reportModuleNotFoundToWatchMode(basePath, extensions) {
246
271
}
247
272
}
248
273
249
- /** @type {Map<Module, Module> } */
250
- const moduleParentCache = new SafeWeakMap ( ) ;
251
274
/**
252
275
* Create a new module instance.
253
276
* @param {string } id
@@ -257,7 +280,7 @@ function Module(id = '', parent) {
257
280
this . id = id ;
258
281
this . path = path . dirname ( id ) ;
259
282
setOwnProperty ( this , 'exports' , { } ) ;
260
- moduleParentCache . set ( this , parent ) ;
283
+ this [ kModuleParent ] = parent ;
261
284
updateChildren ( parent , this , false ) ;
262
285
this . filename = null ;
263
286
this . loaded = false ;
@@ -345,17 +368,19 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
345
368
346
369
/**
347
370
* Get the parent of the current module from our cache.
371
+ * @this {Module}
348
372
*/
349
373
function getModuleParent ( ) {
350
- return moduleParentCache . get ( this ) ;
374
+ return this [ kModuleParent ] ;
351
375
}
352
376
353
377
/**
354
378
* Set the parent of the current module in our cache.
379
+ * @this {Module}
355
380
* @param {Module } value
356
381
*/
357
382
function setModuleParent ( value ) {
358
- moduleParentCache . set ( this , value ) ;
383
+ this [ kModuleParent ] = value ;
359
384
}
360
385
361
386
let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'module' , ( fn ) => {
@@ -1007,15 +1032,18 @@ Module._load = function(request, parent, isMain) {
1007
1032
const cachedModule = Module . _cache [ filename ] ;
1008
1033
if ( cachedModule !== undefined ) {
1009
1034
updateChildren ( parent , cachedModule , true ) ;
1010
- if ( ! cachedModule . loaded ) {
1011
- const parseCachedModule = cjsSourceCache . get ( cachedModule ) ;
1012
- if ( ! parseCachedModule || parseCachedModule . loaded ) {
1013
- return getExportsForCircularRequire ( cachedModule ) ;
1014
- }
1015
- parseCachedModule . loaded = true ;
1016
- } else {
1035
+ if ( cachedModule . loaded ) {
1017
1036
return cachedModule . exports ;
1018
1037
}
1038
+ // If the cached module was finished loading, there are two possible conditions:
1039
+ // 1. the cache entry was created by the ESM loader, or
1040
+ // 2. it is circularly required.
1041
+ // Return a proxy for the cached module's export object if the module is circularly required.
1042
+ if ( cachedModule [ kModuleExportNames ] === undefined || cachedModule [ kModuleCircularVisited ] ) {
1043
+ return getExportsForCircularRequire ( cachedModule ) ;
1044
+ }
1045
+ // This is an ESM loader created cache entry, mark it as visited and fallthrough to loading the module.
1046
+ cachedModule [ kModuleCircularVisited ] = true ;
1019
1047
}
1020
1048
1021
1049
if ( BuiltinModule . canBeRequiredWithoutScheme ( filename ) ) {
@@ -1156,7 +1184,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
1156
1184
const requireStack = [ ] ;
1157
1185
for ( let cursor = parent ;
1158
1186
cursor ;
1159
- cursor = moduleParentCache . get ( cursor ) ) {
1187
+ cursor = cursor [ kModuleParent ] ) {
1160
1188
ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
1161
1189
}
1162
1190
let message = `Cannot find module '${ request } '` ;
@@ -1234,9 +1262,7 @@ Module.prototype.load = function(filename) {
1234
1262
// Create module entry at load time to snapshot exports correctly
1235
1263
const exports = this . exports ;
1236
1264
// Preemptively cache for ESM loader.
1237
- if ( ! cjsExportsCache . has ( this ) ) {
1238
- cjsExportsCache . set ( this , exports ) ;
1239
- }
1265
+ this [ kModuleExport ] = exports ;
1240
1266
} ;
1241
1267
1242
1268
/**
@@ -1365,7 +1391,7 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1365
1391
// Only modules being require()'d really need to avoid TLA.
1366
1392
if ( loadAsESM ) {
1367
1393
// Pass the source into the .mjs extension handler indirectly through the cache.
1368
- cjsSourceCache . set ( this , { source : content } ) ;
1394
+ this [ kModuleSource ] = content ;
1369
1395
loadESMFromCJS ( this , filename ) ;
1370
1396
return ;
1371
1397
}
@@ -1424,11 +1450,11 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
1424
1450
* @returns {string }
1425
1451
*/
1426
1452
function getMaybeCachedSource ( mod , filename ) {
1427
- const cached = cjsSourceCache . get ( mod ) ;
1453
+ // If already analyzed the source, then it will be cached.
1428
1454
let content ;
1429
- if ( cached ?. source ) {
1430
- content = cached . source ;
1431
- cached . source = undefined ;
1455
+ if ( mod [ kModuleSource ] !== undefined ) {
1456
+ content = mod [ kModuleSource ] ;
1457
+ mod [ kModuleSource ] = undefined ;
1432
1458
} else {
1433
1459
// TODO(joyeecheung): we can read a buffer instead to speed up
1434
1460
// compilation.
@@ -1456,7 +1482,7 @@ Module._extensions['.js'] = function(module, filename) {
1456
1482
}
1457
1483
1458
1484
// This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1459
- const parent = moduleParentCache . get ( module ) ;
1485
+ const parent = module [ kModuleParent ] ;
1460
1486
const parentPath = parent ?. filename ;
1461
1487
const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
1462
1488
const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments