@@ -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 entryPointSource : undefined , // Set below.
86110 Module,
@@ -257,8 +281,6 @@ function reportModuleNotFoundToWatchMode(basePath, extensions) {
257281 }
258282}
259283
260- /** @type {Map<Module, Module> } */
261- const moduleParentCache = new SafeWeakMap ( ) ;
262284/**
263285 * Create a new module instance.
264286 * @param {string } id
@@ -268,7 +290,7 @@ function Module(id = '', parent) {
268290 this . id = id ;
269291 this . path = path . dirname ( id ) ;
270292 setOwnProperty ( this , 'exports' , { } ) ;
271- moduleParentCache . set ( this , parent ) ;
293+ this [ kModuleParent ] = parent ;
272294 updateChildren ( parent , this , false ) ;
273295 this . filename = null ;
274296 this . loaded = false ;
@@ -356,17 +378,19 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
356378
357379/**
358380 * Get the parent of the current module from our cache.
381+ * @this {Module}
359382 */
360383function getModuleParent ( ) {
361- return moduleParentCache . get ( this ) ;
384+ return this [ kModuleParent ] ;
362385}
363386
364387/**
365388 * Set the parent of the current module in our cache.
389+ * @this {Module}
366390 * @param {Module } value
367391 */
368392function setModuleParent ( value ) {
369- moduleParentCache . set ( this , value ) ;
393+ this [ kModuleParent ] = value ;
370394}
371395
372396let 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/**
@@ -1406,7 +1427,7 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
14061427 // Only modules being require()'d really need to avoid TLA.
14071428 if ( loadAsESM ) {
14081429 // Pass the source into the .mjs extension handler indirectly through the cache.
1409- requiredESMSourceCache . set ( this , content ) ;
1430+ this [ kModuleSource ] = content ;
14101431 loadESMFromCJS ( this , filename ) ;
14111432 return ;
14121433 }
@@ -1467,15 +1488,15 @@ Module.prototype._compile = function(content, filename, loadAsESM = false) {
14671488 * @returns {string }
14681489 */
14691490function getMaybeCachedSource ( mod , filename ) {
1470- const cached = importedCJSCache . get ( mod ) ;
1491+ // If already analyzed the source, then it will be cached.
14711492 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 ;
14751496 } else {
14761497 // TODO(joyeecheung): we can read a buffer instead to speed up
14771498 // compilation.
1478- content = requiredESMSourceCache . get ( mod ) ?? fs . readFileSync ( filename , 'utf8' ) ;
1499+ content = fs . readFileSync ( filename , 'utf8' ) ;
14791500 }
14801501 return content ;
14811502}
@@ -1499,7 +1520,7 @@ Module._extensions['.js'] = function(module, filename) {
14991520 }
15001521
15011522 // 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 ] ;
15031524 const parentPath = parent ?. filename ;
15041525 const packageJsonPath = path . resolve ( pkg . path , 'package.json' ) ;
15051526 const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments