@@ -50,7 +50,6 @@ const {
5050 ReflectSet,
5151 RegExpPrototypeExec,
5252 SafeMap,
53- SafeWeakMap,
5453 String,
5554 StringPrototypeCharAt,
5655 StringPrototypeCharCodeAt,
@@ -62,25 +61,50 @@ const {
6261 StringPrototypeStartsWith,
6362 Symbol,
6463} = 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' ) ;
6573
6674const { kEvaluated } = internalBinding ( 'module_wrap' ) ;
6775
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 ;
7089/**
71- * Map of already-loaded CJS modules to use .
90+ * { @link Module } export object snapshot for ESM loader .
7291 */
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 ;
7597
7698const kIsMainSymbol = Symbol ( 'kIsMainSymbol' ) ;
7799const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
78100const kRequiredModuleSymbol = Symbol ( 'kRequiredModuleSymbol' ) ;
79101const kIsExecuting = Symbol ( 'kIsExecuting' ) ;
80102// Set first due to cycle with ESM loader functions.
81103module . exports = {
82- cjsExportsCache,
83- importedCJSCache,
104+ kModuleSource,
105+ kModuleExport,
106+ kModuleExportNames,
107+ kModuleCircularVisited,
84108 initializeCJS,
85109 Module,
86110 wrapSafe,
@@ -256,8 +280,6 @@ function reportModuleNotFoundToWatchMode(basePath, extensions) {
256280 }
257281}
258282
259- /** @type {Map<Module, Module> } */
260- const moduleParentCache = new SafeWeakMap ( ) ;
261283/**
262284 * Create a new module instance.
263285 * @param {string } id
@@ -267,7 +289,7 @@ function Module(id = '', parent) {
267289 this . id = id ;
268290 this . path = path . dirname ( id ) ;
269291 setOwnProperty ( this , 'exports' , { } ) ;
270- moduleParentCache . set ( this , parent ) ;
292+ this [ kModuleParent ] = parent ;
271293 updateChildren ( parent , this , false ) ;
272294 this . filename = null ;
273295 this . loaded = false ;
@@ -355,17 +377,19 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
355377
356378/**
357379 * Get the parent of the current module from our cache.
380+ * @this {Module}
358381 */
359382function getModuleParent ( ) {
360- return moduleParentCache . get ( this ) ;
383+ return this [ kModuleParent ] ;
361384}
362385
363386/**
364387 * Set the parent of the current module in our cache.
388+ * @this {Module}
365389 * @param {Module } value
366390 */
367391function setModuleParent ( value ) {
368- moduleParentCache . set ( this , value ) ;
392+ this [ kModuleParent ] = value ;
369393}
370394
371395let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'module' , ( fn ) => {
@@ -955,7 +979,7 @@ function getExportsForCircularRequire(module) {
955979 const requiredESM = module [ kRequiredModuleSymbol ] ;
956980 if ( requiredESM && requiredESM . getStatus ( ) !== kEvaluated ) {
957981 let message = `Cannot require() ES Module ${ module . id } in a cycle.` ;
958- const parent = moduleParentCache . get ( module ) ;
982+ const parent = module [ kModuleParent ] ;
959983 if ( parent ) {
960984 message += ` (from ${ parent . filename } )` ;
961985 }
@@ -1028,25 +1052,24 @@ Module._load = function(request, parent, isMain) {
10281052 const cachedModule = Module . _cache [ filename ] ;
10291053 if ( cachedModule !== undefined ) {
10301054 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 ) {
10481056 return cachedModule . exports ;
10491057 }
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 ;
10501073 }
10511074
10521075 if ( BuiltinModule . canBeRequiredWithoutScheme ( filename ) ) {
@@ -1190,7 +1213,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
11901213 const requireStack = [ ] ;
11911214 for ( let cursor = parent ;
11921215 cursor ;
1193- cursor = moduleParentCache . get ( cursor ) ) {
1216+ cursor = cursor [ kModuleParent ] ) {
11941217 ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
11951218 }
11961219 let message = `Cannot find module '${ request } '` ;
@@ -1268,9 +1291,7 @@ Module.prototype.load = function(filename) {
12681291 // Create module entry at load time to snapshot exports correctly
12691292 const exports = this . exports ;
12701293 // Preemptively cache for ESM loader.
1271- if ( ! cjsExportsCache . has ( this ) ) {
1272- cjsExportsCache . set ( this , exports ) ;
1273- }
1294+ this [ kModuleExport ] = exports ;
12741295} ;
12751296
12761297/**
@@ -1313,7 +1334,7 @@ function loadESMFromCJS(mod, filename) {
13131334 const isMain = mod [ kIsMainSymbol ] ;
13141335 // TODO(joyeecheung): we may want to invent optional special handling for default exports here.
13151336 // 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 ] ) ;
13171338}
13181339
13191340/**
@@ -1399,7 +1420,7 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
13991420 // Only modules being require()'d really need to avoid TLA.
14001421 if ( loadAsESM ) {
14011422 // Pass the source into the .mjs extension handler indirectly through the cache.
1402- requiredESMSourceCache . set ( this , content ) ;
1423+ this [ kModuleSource ] = content ;
14031424 loadESMFromCJS ( this , filename ) ;
14041425 return ;
14051426 }
@@ -1460,15 +1481,15 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
14601481 * @returns {string }
14611482 */
14621483function getMaybeCachedSource ( mod , filename ) {
1463- const cached = importedCJSCache . get ( mod ) ;
1484+ // If already analyzed the source, then it will be cached.
14641485 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 ;
14681489 } else {
14691490 // TODO(joyeecheung): we can read a buffer instead to speed up
14701491 // compilation.
1471- content = requiredESMSourceCache . get ( mod ) ?? fs . readFileSync ( filename , 'utf8' ) ;
1492+ content = fs . readFileSync ( filename , 'utf8' ) ;
14721493 }
14731494 return content ;
14741495}
@@ -1492,7 +1513,7 @@ Module._extensions['.js'] = function(module, filename) {
14921513 }
14931514
14941515 // 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 ] ;
14961517 const parentPath = parent ?. filename ;
14971518 const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
14981519 const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments