@@ -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,15 @@ 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, 
80+   makeRequireWithPolicy, 
7981} ; 
8082
83+ const  is_main_symbol  =  Symbol ( 'is_main_symbol' ) ; 
84+ 
8185const  {  BuiltinModule }  =  require ( 'internal/bootstrap/realm' ) ; 
8286const  { 
8387  maybeCacheSourceMap, 
@@ -98,7 +102,6 @@ const {
98102  containsModuleSyntax, 
99103  compileFunctionForCJSLoader, 
100104}  =  internalBinding ( 'contextify' ) ; 
101- 
102105const  assert  =  require ( 'internal/assert' ) ; 
103106const  fs  =  require ( 'fs' ) ; 
104107const  path  =  require ( 'path' ) ; 
@@ -107,7 +110,6 @@ const { safeGetenv } = internalBinding('credentials');
107110const  { 
108111  privateSymbols : { 
109112    require_private_symbol, 
110-     host_defined_option_symbol, 
111113  } , 
112114}  =  internalBinding ( 'util' ) ; 
113115const  { 
@@ -396,6 +398,10 @@ function initializeCJS() {
396398  // TODO(joyeecheung): deprecate this in favor of a proper hook? 
397399  Module . runMain  = 
398400    require ( 'internal/modules/run_main' ) . executeUserEntryPoint ; 
401+ 
402+   if  ( getOptionValue ( '--experimental-require-module' ) )  { 
403+     Module . _extensions [ '.mjs' ]  =  loadESMFromCJS ; 
404+   } 
399405} 
400406
401407// Given a module name, and a list of paths to test, returns the first 
@@ -988,7 +994,7 @@ Module._load = function(request, parent, isMain) {
988994  if  ( cachedModule  !==  undefined )  { 
989995    updateChildren ( parent ,  cachedModule ,  true ) ; 
990996    if  ( ! cachedModule . loaded )  { 
991-       const  parseCachedModule  =  cjsParseCache . get ( cachedModule ) ; 
997+       const  parseCachedModule  =  cjsSourceCache . get ( cachedModule ) ; 
992998      if  ( ! parseCachedModule  ||  parseCachedModule . loaded )  { 
993999        return  getExportsForCircularRequire ( cachedModule ) ; 
9941000      } 
@@ -1010,6 +1016,9 @@ Module._load = function(request, parent, isMain) {
10101016    setOwnProperty ( process ,  'mainModule' ,  module ) ; 
10111017    setOwnProperty ( module . require ,  'main' ,  process . mainModule ) ; 
10121018    module . id  =  '.' ; 
1019+     module [ is_main_symbol ]  =  true ; 
1020+   }  else  { 
1021+     module [ is_main_symbol ]  =  false ; 
10131022  } 
10141023
10151024  reportModuleToWatchMode ( filename ) ; 
@@ -1270,57 +1279,96 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache) {
12701279    ) ; 
12711280
12721281    // Cache the source map for the module if present. 
1273-     if  ( script . sourceMapURL )  { 
1274-       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  script . sourceMapURL ) ; 
1282+     const  {  sourceMapURL }  =  script ; 
1283+     if  ( sourceMapURL )  { 
1284+       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  sourceMapURL ) ; 
12751285    } 
12761286
1277-     return  runScriptInThisContext ( script ,  true ,  false ) ; 
1287+     return  { 
1288+       __proto__ : null , 
1289+       function : runScriptInThisContext ( script ,  true ,  false ) , 
1290+       sourceMapURL, 
1291+       retryAsESM : false , 
1292+     } ; 
12781293  } 
12791294
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-     } 
1295+   const  result  =  compileFunctionForCJSLoader ( content ,  filename ) ; 
12901296
1291-     // Cache the source map for the module if present. 
1292-     if  ( result . sourceMapURL )  { 
1293-       maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  result . sourceMapURL ) ; 
1294-     } 
1297+   // cachedDataRejected is only set for cache coming from SEA. 
1298+   if  ( codeCache  && 
1299+       result . cachedDataRejected  !==  false  && 
1300+       internalBinding ( 'sea' ) . isSea ( ) )  { 
1301+     process . emitWarning ( 'Code cache data rejected.' ) ; 
1302+   } 
12951303
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 ; 
1304+   // Cache the source map for the module if present. 
1305+   if  ( result . sourceMapURL )  { 
1306+     maybeCacheSourceMap ( filename ,  content ,  this ,  false ,  undefined ,  result . sourceMapURL ) ; 
1307+   } 
1308+ 
1309+   return  result ; 
1310+ } 
1311+ 
1312+ // Resolve and evaluate as ESM, synchronously. 
1313+ function  loadESMFromCJS ( mod ,  filename )  { 
1314+   const  source  =  getMaybeCachedSource ( mod ,  filename ) ; 
1315+   const  cascadedLoader  =  require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ; 
1316+   // We are still using the CJS's resolution here. 
1317+   const  url  =  pathToFileURL ( filename ) . href ; 
1318+   const  isMain  =  mod [ is_main_symbol ] ; 
1319+   // TODO(joyeecheung): maybe we can do some special handling for default here. Maybe we don't. 
1320+   mod . exports  =  cascadedLoader . importSyncForRequire ( url ,  source ,  isMain ) ; 
1321+ } 
1322+ 
1323+ /** 
1324+  * Create a require function for this module, apply policy if necessary. 
1325+  * @param  {Module } module 
1326+  * @param  {string } moduleURL 
1327+  * @returns  {Function } 
1328+  */ 
1329+ function  makeRequireWithPolicy ( module ,  moduleURL )  { 
1330+   const  manifest  =  policy ( ) ?. manifest ; 
1331+   let  redirects ; 
1332+   if  ( manifest )  { 
1333+     redirects  =  manifest . getDependencyMapper ( moduleURL ) ; 
13031334  } 
1335+   return  makeRequireFunction ( module ,  redirects ) ; 
13041336} 
13051337
13061338/** 
13071339 * Run the file contents in the correct scope or sandbox. Expose the correct helper variables (`require`, `module`, 
13081340 * `exports`) to the file. Returns exception, if any. 
13091341 * @param  {string } content The source code of the module 
13101342 * @param  {string } filename The file path of the module 
1343+  * @param  {boolean } loadAsESM Whether it's known to be ESM - i.e. suffix is .mjs. 
13111344 */ 
1312- Module . prototype . _compile  =  function ( content ,  filename )  { 
1345+ Module . prototype . _compile  =  function ( content ,  filename ,   loadAsESM   =   false )  { 
13131346  let  moduleURL ; 
1314-   let  redirects ; 
13151347  const  manifest  =  policy ( ) ?. manifest ; 
13161348  if  ( manifest )  { 
13171349    moduleURL  =  pathToFileURL ( filename ) ; 
1318-     redirects  =  manifest . getDependencyMapper ( moduleURL ) ; 
13191350    manifest . assertIntegrity ( moduleURL ,  content ) ; 
13201351  } 
13211352
1322-   const  compiledWrapper  =  wrapSafe ( filename ,  content ,  this ) ; 
1353+   // TODO(joyeecheung): when the module is the entry point, consider allowing TLA. 
1354+   // Only modules being require()'d really need to avoid TLA. 
1355+   let  compiledWrapper ; 
1356+   if  ( ! loadAsESM )  { 
1357+     const  result  =  wrapSafe ( filename ,  content ,  this ) ; 
1358+     compiledWrapper  =  result . function ; 
1359+     loadAsESM  =  result . retryAsESM ; 
1360+   } 
13231361
1362+   if  ( loadAsESM )  { 
1363+     // Pass the source into the .mjs extension handler indirectly through the cache. 
1364+     cjsSourceCache . set ( this ,  content ) ; 
1365+     loadESMFromCJS ( this ,  filename ) ; 
1366+     return ; 
1367+   } 
1368+ 
1369+   // TODO(joyeecheung): the detection below is unnecessarily complex. Maybe just 
1370+   // use the is_main_symbol, or a break_on_start_symbol that gets passed from 
1371+   // higher level instead of doing hacky detecion here. 
13241372  let  inspectorWrapper  =  null ; 
13251373  if  ( getOptionValue ( '--inspect-brk' )  &&  process . _eval  ==  null )  { 
13261374    if  ( ! resolvedArgv )  { 
@@ -1344,8 +1392,9 @@ Module.prototype._compile = function(content, filename) {
13441392      inspectorWrapper  =  internalBinding ( 'inspector' ) . callAndPauseOnStart ; 
13451393    } 
13461394  } 
1395+ 
13471396  const  dirname  =  path . dirname ( filename ) ; 
1348-   const  require  =  makeRequireFunction ( this ,  redirects ) ; 
1397+   const  require  =  makeRequireWithPolicy ( this ,  moduleURL ) ; 
13491398  let  result ; 
13501399  const  exports  =  this . exports ; 
13511400  const  thisValue  =  exports ; 
@@ -1363,25 +1412,37 @@ Module.prototype._compile = function(content, filename) {
13631412  return  result ; 
13641413} ; 
13651414
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 ) ; 
1415+ function  getMaybeCachedSource ( mod ,  filename )  { 
1416+   const  cached  =  cjsSourceCache . get ( mod ) ; 
13741417  let  content ; 
13751418  if  ( cached ?. source )  { 
13761419    content  =  cached . source ; 
13771420    cached . source  =  undefined ; 
13781421  }  else  { 
1422+     // TODO(joyeecheung): read a buffer. 
13791423    content  =  fs . readFileSync ( filename ,  'utf8' ) ; 
13801424  } 
1425+   return  content ; 
1426+ } 
1427+ 
1428+ /** 
1429+  * Native handler for `.js` files. 
1430+  * @param  {Module } module The module to compile 
1431+  * @param  {string } filename The file path of the module 
1432+  */ 
1433+ Module . _extensions [ '.js' ]  =  function ( module ,  filename )  { 
1434+   // If already analyzed the source, then it will be cached. 
1435+   const  content  =  getMaybeCachedSource ( module ,  filename ) ; 
1436+ 
13811437  if  ( StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
13821438    const  pkg  =  packageJsonReader . getNearestParentPackageJSON ( filename ) ; 
13831439    // Function require shouldn't be used in ES modules. 
13841440    if  ( pkg ?. data . type  ===  'module' )  { 
1441+       if  ( getOptionValue ( '--experimental-require-module' ) )  { 
1442+         module . _compile ( content ,  filename ,  true ) ; 
1443+         return ; 
1444+       } 
1445+ 
13851446      // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed. 
13861447      const  parent  =  moduleParentCache . get ( module ) ; 
13871448      const  parentPath  =  parent ?. filename ; 
@@ -1414,7 +1475,8 @@ Module._extensions['.js'] = function(module, filename) {
14141475      throw  err ; 
14151476    } 
14161477  } 
1417-   module . _compile ( content ,  filename ) ; 
1478+ 
1479+   module . _compile ( content ,  filename ,  false ) ; 
14181480} ; 
14191481
14201482/** 
0 commit comments