@@ -60,10 +60,11 @@ const {
6060  StringPrototypeSlice, 
6161  StringPrototypeSplit, 
6262  StringPrototypeStartsWith, 
63+   Symbol, 
6364}  =  primordials ; 
6465
65- // Map used to store CJS parsing data. 
66- const  cjsParseCache  =  new  SafeWeakMap ( ) ; 
66+ // Map used to store CJS parsing data or for ESM loading . 
67+ const  cjsSourceCache  =  new  SafeWeakMap ( ) ; 
6768/** 
6869 * Map of already-loaded CJS modules to use. 
6970 */ 
@@ -72,12 +73,14 @@ const cjsExportsCache = new SafeWeakMap();
7273// Set first due to cycle with ESM loader functions. 
7374module . exports  =  { 
7475  cjsExportsCache, 
75-   cjsParseCache , 
76+   cjsSourceCache , 
7677  initializeCJS, 
7778  Module, 
7879  wrapSafe, 
7980} ; 
8081
82+ const  is_main_symbol  =  Symbol ( 'is_main_symbol' ) ; 
83+ 
8184const  {  BuiltinModule }  =  require ( 'internal/bootstrap/realm' ) ; 
8285const  { 
8386  maybeCacheSourceMap, 
@@ -98,7 +101,6 @@ const {
98101  containsModuleSyntax, 
99102  compileFunctionForCJSLoader, 
100103}  =  internalBinding ( 'contextify' ) ; 
101- 
102104const  assert  =  require ( 'internal/assert' ) ; 
103105const  fs  =  require ( 'fs' ) ; 
104106const  path  =  require ( 'path' ) ; 
@@ -107,7 +109,6 @@ const { safeGetenv } = internalBinding('credentials');
107109const  { 
108110  privateSymbols : { 
109111    require_private_symbol, 
110-     host_defined_option_symbol, 
111112  } , 
112113}  =  internalBinding ( 'util' ) ; 
113114const  { 
@@ -396,6 +397,10 @@ function initializeCJS() {
396397  // TODO(joyeecheung): deprecate this in favor of a proper hook? 
397398  Module . runMain  = 
398399    require ( 'internal/modules/run_main' ) . executeUserEntryPoint ; 
400+ 
401+   if  ( getOptionValue ( '--experimental-require-module' ) )  { 
402+     Module . _extensions [ '.mjs' ]  =  loadESMFromCJS ; 
403+   } 
399404} 
400405
401406// Given a module name, and a list of paths to test, returns the first 
@@ -988,7 +993,7 @@ Module._load = function(request, parent, isMain) {
988993  if  ( cachedModule  !==  undefined )  { 
989994    updateChildren ( parent ,  cachedModule ,  true ) ; 
990995    if  ( ! cachedModule . loaded )  { 
991-       const  parseCachedModule  =  cjsParseCache . get ( cachedModule ) ; 
996+       const  parseCachedModule  =  cjsSourceCache . get ( cachedModule ) ; 
992997      if  ( ! parseCachedModule  ||  parseCachedModule . loaded )  { 
993998        return  getExportsForCircularRequire ( cachedModule ) ; 
994999      } 
@@ -1010,6 +1015,9 @@ Module._load = function(request, parent, isMain) {
10101015    setOwnProperty ( process ,  'mainModule' ,  module ) ; 
10111016    setOwnProperty ( module . require ,  'main' ,  process . mainModule ) ; 
10121017    module . id  =  '.' ; 
1018+     module [ is_main_symbol ]  =  true ; 
1019+   }  else  { 
1020+     module [ is_main_symbol ]  =  false ; 
10131021  } 
10141022
10151023  reportModuleToWatchMode ( filename ) ; 
@@ -1270,46 +1278,55 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache) {
12701278    ) ; 
12711279
12721280    // Cache the source map for the module if present. 
1273-     if  ( script . sourceMapURL )  { 
1274-       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  script . sourceMapURL ) ; 
1281+     const  {  sourceMapURL }  =  script ; 
1282+     if  ( sourceMapURL )  { 
1283+       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  sourceMapURL ) ; 
12751284    } 
12761285
1277-     return  runScriptInThisContext ( script ,  true ,  false ) ; 
1286+     return  { 
1287+       __proto__ : null , 
1288+       function : runScriptInThisContext ( script ,  true ,  false ) , 
1289+       sourceMapURL, 
1290+       retryAsESM : false , 
1291+     } ; 
12781292  } 
12791293
1280-   try  { 
1281-     const  result  =  compileFunctionForCJSLoader ( content ,  filename ) ; 
1282-     result . function [ host_defined_option_symbol ]  =  hostDefinedOptionId ; 
1283- 
1284-     // cachedDataRejected is only set for cache coming from SEA. 
1285-     if  ( codeCache  && 
1286-         result . cachedDataRejected  !==  false  && 
1287-         internalBinding ( 'sea' ) . isSea ( ) )  { 
1288-       process . emitWarning ( 'Code cache data rejected.' ) ; 
1289-     } 
1294+   const  result  =  compileFunctionForCJSLoader ( content ,  filename ) ; 
12901295
1291-     // Cache the source map for the module if present. 
1292-     if  ( result . sourceMapURL )  { 
1293-       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  result . sourceMapURL ) ; 
1294-     } 
1296+   // cachedDataRejected is only set for cache coming from SEA. 
1297+   if  ( codeCache  && 
1298+       result . cachedDataRejected  !==  false  && 
1299+       internalBinding ( 'sea' ) . isSea ( ) )  { 
1300+     process . emitWarning ( 'Code cache data rejected.' ) ; 
1301+   } 
12951302
1296-     return  result . function ; 
1297-   }  catch  ( err )  { 
1298-     if  ( process . mainModule  ===  cjsModuleInstance )  { 
1299-       const  {  enrichCJSError }  =  require ( 'internal/modules/esm/translators' ) ; 
1300-       enrichCJSError ( err ,  content ,  filename ) ; 
1301-     } 
1302-     throw  err ; 
1303+   // Cache the source map for the module if present. 
1304+   if  ( result . sourceMapURL )  { 
1305+     maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  result . sourceMapURL ) ; 
13031306  } 
1307+ 
1308+   return  result ; 
1309+ } 
1310+ 
1311+ // Resolve and evaluate as ESM, synchronously. 
1312+ function  loadESMFromCJS ( mod ,  filename )  { 
1313+   const  source  =  getMaybeCachedSource ( mod ,  filename ) ; 
1314+   const  cascadedLoader  =  require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ; 
1315+   // We are still using the CJS's resolution here. 
1316+   const  url  =  pathToFileURL ( filename ) . href ; 
1317+   const  isMain  =  mod [ is_main_symbol ] ; 
1318+   // TODO(joyeecheung): maybe we can do some special handling for default here. Maybe we don't. 
1319+   mod . exports  =  cascadedLoader . importSyncForRequire ( url ,  source ,  isMain ) ; 
13041320} 
13051321
13061322/** 
13071323 * Run the file contents in the correct scope or sandbox. Expose the correct helper variables (`require`, `module`, 
13081324 * `exports`) to the file. Returns exception, if any. 
13091325 * @param  {string } content The source code of the module 
13101326 * @param  {string } filename The file path of the module 
1327+  * @param  {boolean } loadAsESM Whether it's known to be ESM - i.e. suffix is .mjs. 
13111328 */ 
1312- Module . prototype . _compile  =  function ( content ,  filename )  { 
1329+ Module . prototype . _compile  =  function ( content ,  filename ,   loadAsESM   =   false )  { 
13131330  let  moduleURL ; 
13141331  let  redirects ; 
13151332  const  manifest  =  policy ( ) ?. manifest ; 
@@ -1319,8 +1336,25 @@ Module.prototype._compile = function(content, filename) {
13191336    manifest . assertIntegrity ( moduleURL ,  content ) ; 
13201337  } 
13211338
1322-   const  compiledWrapper  =  wrapSafe ( filename ,  content ,  this ) ; 
1339+   // TODO(joyeecheung): when the module is the entry point, consider allowing TLA. 
1340+   // Only modules being require()'d really need to avoid TLA. 
1341+   let  compiledWrapper ; 
1342+   if  ( ! loadAsESM )  { 
1343+     const  result  =  wrapSafe ( filename ,  content ,  this ) ; 
1344+     compiledWrapper  =  result . function ; 
1345+     loadAsESM  =  result . retryAsESM ; 
1346+   } 
13231347
1348+   if  ( loadAsESM )  { 
1349+     // Pass the source into the .mjs extension handler indirectly through the cache. 
1350+     cjsSourceCache . set ( this ,  content ) ; 
1351+     loadESMFromCJS ( this ,  filename ) ; 
1352+     return ; 
1353+   } 
1354+ 
1355+   // TODO(joyeecheung): the detection below is unnecessarily complex. Maybe just 
1356+   // use the is_main_symbol, or a break_on_start_symbol that gets passed from 
1357+   // higher level instead of doing hacky detecion here. 
13241358  let  inspectorWrapper  =  null ; 
13251359  if  ( getOptionValue ( '--inspect-brk' )  &&  process . _eval  ==  null )  { 
13261360    if  ( ! resolvedArgv )  { 
@@ -1344,6 +1378,7 @@ Module.prototype._compile = function(content, filename) {
13441378      inspectorWrapper  =  internalBinding ( 'inspector' ) . callAndPauseOnStart ; 
13451379    } 
13461380  } 
1381+ 
13471382  const  dirname  =  path . dirname ( filename ) ; 
13481383  const  require  =  makeRequireFunction ( this ,  redirects ) ; 
13491384  let  result ; 
@@ -1363,25 +1398,37 @@ Module.prototype._compile = function(content, filename) {
13631398  return  result ; 
13641399} ; 
13651400
1366- /** 
1367-  * Native handler for `.js` files. 
1368-  * @param  {Module } module The module to compile 
1369-  * @param  {string } filename The file path of the module 
1370-  */ 
1371- Module . _extensions [ '.js' ]  =  function ( module ,  filename )  { 
1372-   // If already analyzed the source, then it will be cached. 
1373-   const  cached  =  cjsParseCache . get ( module ) ; 
1401+ function  getMaybeCachedSource ( mod ,  filename )  { 
1402+   const  cached  =  cjsSourceCache . get ( mod ) ; 
13741403  let  content ; 
13751404  if  ( cached ?. source )  { 
13761405    content  =  cached . source ; 
13771406    cached . source  =  undefined ; 
13781407  }  else  { 
1408+     // TODO(joyeecheung): read a buffer. 
13791409    content  =  fs . readFileSync ( filename ,  'utf8' ) ; 
13801410  } 
1411+   return  content ; 
1412+ } 
1413+ 
1414+ /** 
1415+  * Native handler for `.js` files. 
1416+  * @param  {Module } module The module to compile 
1417+  * @param  {string } filename The file path of the module 
1418+  */ 
1419+ Module . _extensions [ '.js' ]  =  function ( module ,  filename )  { 
1420+   // If already analyzed the source, then it will be cached. 
1421+   const  content  =  getMaybeCachedSource ( module ,  filename ) ; 
1422+ 
13811423  if  ( StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
13821424    const  pkg  =  packageJsonReader . getNearestParentPackageJSON ( filename ) ; 
13831425    // Function require shouldn't be used in ES modules. 
13841426    if  ( pkg ?. data . type  ===  'module' )  { 
1427+       if  ( getOptionValue ( '--experimental-require-module' ) )  { 
1428+         module . _compile ( content ,  filename ,  true ) ; 
1429+         return ; 
1430+       } 
1431+ 
13851432      // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed. 
13861433      const  parent  =  moduleParentCache . get ( module ) ; 
13871434      const  parentPath  =  parent ?. filename ; 
@@ -1414,7 +1461,8 @@ Module._extensions['.js'] = function(module, filename) {
14141461      throw  err ; 
14151462    } 
14161463  } 
1417-   module . _compile ( content ,  filename ) ; 
1464+ 
1465+   module . _compile ( content ,  filename ,  false ) ; 
14181466} ; 
14191467
14201468/** 
0 commit comments