@@ -60,6 +60,7 @@ const {
6060  StringPrototypeSlice, 
6161  StringPrototypeSplit, 
6262  StringPrototypeStartsWith, 
63+   Symbol, 
6364}  =  primordials ; 
6465
6566// Map used to store CJS parsing data. 
@@ -107,7 +108,6 @@ const { safeGetenv } = internalBinding('credentials');
107108const  { 
108109  privateSymbols : { 
109110    require_private_symbol, 
110-     host_defined_option_symbol, 
111111  } , 
112112}  =  internalBinding ( 'util' ) ; 
113113const  { 
@@ -161,6 +161,8 @@ let requireDepth = 0;
161161let  isPreloading  =  false ; 
162162let  statCache  =  null ; 
163163
164+ const  is_main_symbol  =  Symbol ( 'is-main-module' ) ; 
165+ 
164166/** 
165167 * Our internal implementation of `require`. 
166168 * @param  {Module } module Parent module of what is being required 
@@ -271,6 +273,7 @@ function Module(id = '', parent) {
271273    setOwnProperty ( this . __proto__ ,  'require' ,  makeRequireFunction ( this ,  redirects ) ) ; 
272274  } 
273275  this [ require_private_symbol ]  =  internalRequire ; 
276+   this [ is_main_symbol ]  =  false ;   // Set to true by the entry point handler. 
274277} 
275278
276279/** @type  {Record<string, Module> } */ 
@@ -396,6 +399,10 @@ function initializeCJS() {
396399  // TODO(joyeecheung): deprecate this in favor of a proper hook? 
397400  Module . runMain  = 
398401    require ( 'internal/modules/run_main' ) . executeUserEntryPoint ; 
402+ 
403+   if  ( getOptionValue ( '--experimental-require-module' ) )  { 
404+     Module . _extensions [ '.mjs' ]  =  loadESMFromCJS ; 
405+   } 
399406} 
400407
401408// Given a module name, and a list of paths to test, returns the first 
@@ -1010,6 +1017,7 @@ Module._load = function(request, parent, isMain) {
10101017    setOwnProperty ( process ,  'mainModule' ,  module ) ; 
10111018    setOwnProperty ( module . require ,  'main' ,  process . mainModule ) ; 
10121019    module . id  =  '.' ; 
1020+     module [ is_main_symbol ]  =  true ; 
10131021  } 
10141022
10151023  reportModuleToWatchMode ( filename ) ; 
@@ -1270,46 +1278,58 @@ 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  cascadedLoader  =  require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ; 
1314+   // Note that we are still using the CJS's path resolution here. 
1315+   const  parent  =  moduleParentCache . get ( mod ) ?. filename ; 
1316+   const  base  =  parent  ? pathToFileURL ( parent )  : parent ; 
1317+   // console.log('loadESMFromCJS', mod, filename, base); 
1318+   const  specifier  =  mod [ is_main_symbol ]  ? pathToFileURL ( mod . filename )  : mod . id ; 
1319+   const  job  =  cascadedLoader . getModuleJobSync ( specifier ,  base ,  kEmptyObject ,  'from-cjs-error' ) ; 
1320+   const  {  namespace }  =  job . runSync ( ) ; 
1321+   // TODO(joyeecheung): maybe we can do some special handling for default here. Maybe we don't. 
1322+   mod . exports  =  namespace ; 
13041323} 
13051324
13061325/** 
13071326 * Run the file contents in the correct scope or sandbox. Expose the correct helper variables (`require`, `module`, 
13081327 * `exports`) to the file. Returns exception, if any. 
13091328 * @param  {string } content The source code of the module 
13101329 * @param  {string } filename The file path of the module 
1330+  * @param  {boolean } loadAsESM Whether it's known to be ESM - i.e. suffix is .mjs. 
13111331 */ 
1312- Module . prototype . _compile  =  function ( content ,  filename )  { 
1332+ Module . prototype . _compile  =  function ( content ,  filename ,   loadAsESM   =   false )  { 
13131333  let  moduleURL ; 
13141334  let  redirects ; 
13151335  const  manifest  =  policy ( ) ?. manifest ; 
@@ -1319,8 +1339,21 @@ Module.prototype._compile = function(content, filename) {
13191339    manifest . assertIntegrity ( moduleURL ,  content ) ; 
13201340  } 
13211341
1322-   const  compiledWrapper  =  wrapSafe ( filename ,  content ,  this ) ; 
1342+   let  compiledWrapper ; 
1343+   if  ( ! loadAsESM )  { 
1344+     const  result  =  wrapSafe ( filename ,  content ,  this ) ; 
1345+     compiledWrapper  =  result . function ; 
1346+     loadAsESM  =  result . retryAsESM ; 
1347+   } 
1348+ 
1349+   if  ( loadAsESM )  { 
1350+     loadESMFromCJS ( this ) ; 
1351+     return ; 
1352+   } 
13231353
1354+   // TODO(joyeecheung): the detection below is unnecessarily complex. Maybe just 
1355+   // use the is_main_symbol, or a break_on_start_symbol that gets passed from 
1356+   // higher level instead of doing hacky detecion here. 
13241357  let  inspectorWrapper  =  null ; 
13251358  if  ( getOptionValue ( '--inspect-brk' )  &&  process . _eval  ==  null )  { 
13261359    if  ( ! resolvedArgv )  { 
@@ -1344,6 +1377,7 @@ Module.prototype._compile = function(content, filename) {
13441377      inspectorWrapper  =  internalBinding ( 'inspector' ) . callAndPauseOnStart ; 
13451378    } 
13461379  } 
1380+ 
13471381  const  dirname  =  path . dirname ( filename ) ; 
13481382  const  require  =  makeRequireFunction ( this ,  redirects ) ; 
13491383  let  result ; 
@@ -1370,6 +1404,7 @@ Module.prototype._compile = function(content, filename) {
13701404 */ 
13711405Module . _extensions [ '.js' ]  =  function ( module ,  filename )  { 
13721406  // If already analyzed the source, then it will be cached. 
1407+   // TODO(joyeecheung): pass as buffer. 
13731408  const  cached  =  cjsParseCache . get ( module ) ; 
13741409  let  content ; 
13751410  if  ( cached ?. source )  { 
@@ -1378,7 +1413,8 @@ Module._extensions['.js'] = function(module, filename) {
13781413  }  else  { 
13791414    content  =  fs . readFileSync ( filename ,  'utf8' ) ; 
13801415  } 
1381-   if  ( StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
1416+   if  ( ! getOptionValue ( '--experimental-require-module' )  && 
1417+       StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
13821418    const  pkg  =  packageJsonReader . getNearestParentPackageJSON ( filename ) ; 
13831419    // Function require shouldn't be used in ES modules. 
13841420    if  ( pkg ?. data . type  ===  'module' )  { 
@@ -1414,7 +1450,8 @@ Module._extensions['.js'] = function(module, filename) {
14141450      throw  err ; 
14151451    } 
14161452  } 
1417-   module . _compile ( content ,  filename ) ; 
1453+ 
1454+   module . _compile ( content ,  filename ,  false ) ; 
14181455} ; 
14191456
14201457/** 
0 commit comments