@@ -60,6 +60,7 @@ const {
6060  StringPrototypeSlice, 
6161  StringPrototypeSplit, 
6262  StringPrototypeStartsWith, 
63+   Symbol, 
6364}  =  primordials ; 
6465
6566// Map used to store CJS parsing data. 
@@ -76,6 +77,7 @@ module.exports = {
7677  initializeCJS, 
7778  Module, 
7879  wrapSafe, 
80+   makeRequireForCJS, 
7981} ; 
8082
8183const  {  BuiltinModule }  =  require ( 'internal/bootstrap/realm' ) ; 
@@ -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  { 
@@ -161,6 +162,8 @@ let requireDepth = 0;
161162let  isPreloading  =  false ; 
162163let  statCache  =  null ; 
163164
165+ const  is_main_symbol  =  Symbol ( 'is-main-module' ) ; 
166+ 
164167/** 
165168 * Our internal implementation of `require`. 
166169 * @param  {Module } module Parent module of what is being required 
@@ -271,6 +274,7 @@ function Module(id = '', parent) {
271274    setOwnProperty ( this . __proto__ ,  'require' ,  makeRequireFunction ( this ,  redirects ) ) ; 
272275  } 
273276  this [ require_private_symbol ]  =  internalRequire ; 
277+   this [ is_main_symbol ]  =  false ;   // Set to true by the entry point handler. 
274278} 
275279
276280/** @type  {Record<string, Module> } */ 
@@ -396,6 +400,10 @@ function initializeCJS() {
396400  // TODO(joyeecheung): deprecate this in favor of a proper hook? 
397401  Module . runMain  = 
398402    require ( 'internal/modules/run_main' ) . executeUserEntryPoint ; 
403+ 
404+   if  ( getOptionValue ( '--experimental-require-module' ) )  { 
405+     Module . _extensions [ '.mjs' ]  =  loadESMFromCJS ; 
406+   } 
399407} 
400408
401409// Given a module name, and a list of paths to test, returns the first 
@@ -1010,6 +1018,7 @@ Module._load = function(request, parent, isMain) {
10101018    setOwnProperty ( process ,  'mainModule' ,  module ) ; 
10111019    setOwnProperty ( module . require ,  'main' ,  process . mainModule ) ; 
10121020    module . id  =  '.' ; 
1021+     module [ is_main_symbol ]  =  true ; 
10131022  } 
10141023
10151024  reportModuleToWatchMode ( filename ) ; 
@@ -1270,57 +1279,89 @@ 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 ) ; 
13031307  } 
1308+ 
1309+   return  result ; 
1310+ } 
1311+ 
1312+ // Resolve and evaluate as ESM, synchronously. 
1313+ function  loadESMFromCJS ( mod ,  filename )  { 
1314+   const  cascadedLoader  =  require ( 'internal/modules/esm/loader' ) . getOrInitializeCascadedLoader ( ) ; 
1315+   // Note that we are still using the CJS's path resolution here. 
1316+   const  parent  =  moduleParentCache . get ( mod ) ?. filename ; 
1317+   const  base  =  parent  ? pathToFileURL ( parent )  : parent ; 
1318+   // console.log('loadESMFromCJS', mod, filename, base); 
1319+   const  specifier  =  mod [ is_main_symbol ]  ? pathToFileURL ( mod . filename )  : mod . id ; 
1320+   const  job  =  cascadedLoader . getModuleJobSync ( specifier ,  base ,  kEmptyObject ,  'from-cjs-error' ) ; 
1321+   const  {  namespace }  =  job . runSync ( ) ; 
1322+   // TODO(joyeecheung): maybe we can do some special handling for default here. Maybe we don't. 
1323+   mod . exports  =  namespace ; 
1324+ } 
1325+ 
1326+ function  makeRequireForCJS ( module ,  moduleURL )  { 
1327+   const  manifest  =  policy ( ) ?. manifest ; 
1328+   let  redirects ; 
1329+   if  ( manifest )  { 
1330+     redirects  =  manifest . getDependencyMapper ( moduleURL ) ; 
1331+   } 
1332+   return  makeRequireFunction ( module ,  redirects ) ; 
13041333} 
13051334
13061335/** 
13071336 * Run the file contents in the correct scope or sandbox. Expose the correct helper variables (`require`, `module`, 
13081337 * `exports`) to the file. Returns exception, if any. 
13091338 * @param  {string } content The source code of the module 
13101339 * @param  {string } filename The file path of the module 
1340+  * @param  {boolean } loadAsESM Whether it's known to be ESM - i.e. suffix is .mjs. 
13111341 */ 
1312- Module . prototype . _compile  =  function ( content ,  filename )  { 
1342+ Module . prototype . _compile  =  function ( content ,  filename ,   loadAsESM   =   false )  { 
13131343  let  moduleURL ; 
1314-   let  redirects ; 
13151344  const  manifest  =  policy ( ) ?. manifest ; 
13161345  if  ( manifest )  { 
13171346    moduleURL  =  pathToFileURL ( filename ) ; 
1318-     redirects  =  manifest . getDependencyMapper ( moduleURL ) ; 
13191347    manifest . assertIntegrity ( moduleURL ,  content ) ; 
13201348  } 
13211349
1322-   const  compiledWrapper  =  wrapSafe ( filename ,  content ,  this ) ; 
1350+   let  compiledWrapper ; 
1351+   if  ( ! loadAsESM )  { 
1352+     const  result  =  wrapSafe ( filename ,  content ,  this ) ; 
1353+     compiledWrapper  =  result . function ; 
1354+     loadAsESM  =  result . retryAsESM ; 
1355+   } 
13231356
1357+   if  ( loadAsESM )  { 
1358+     loadESMFromCJS ( this ) ; 
1359+     return ; 
1360+   } 
1361+ 
1362+   // TODO(joyeecheung): the detection below is unnecessarily complex. Maybe just 
1363+   // use the is_main_symbol, or a break_on_start_symbol that gets passed from 
1364+   // higher level instead of doing hacky detecion here. 
13241365  let  inspectorWrapper  =  null ; 
13251366  if  ( getOptionValue ( '--inspect-brk' )  &&  process . _eval  ==  null )  { 
13261367    if  ( ! resolvedArgv )  { 
@@ -1344,8 +1385,9 @@ Module.prototype._compile = function(content, filename) {
13441385      inspectorWrapper  =  internalBinding ( 'inspector' ) . callAndPauseOnStart ; 
13451386    } 
13461387  } 
1388+ 
13471389  const  dirname  =  path . dirname ( filename ) ; 
1348-   const  require  =  makeRequireFunction ( this ,  redirects ) ; 
1390+   const  require  =  makeRequireForCJS ( this ,  moduleURL ) ; 
13491391  let  result ; 
13501392  const  exports  =  this . exports ; 
13511393  const  thisValue  =  exports ; 
@@ -1370,6 +1412,7 @@ Module.prototype._compile = function(content, filename) {
13701412 */ 
13711413Module . _extensions [ '.js' ]  =  function ( module ,  filename )  { 
13721414  // If already analyzed the source, then it will be cached. 
1415+   // TODO(joyeecheung): pass as buffer. 
13731416  const  cached  =  cjsParseCache . get ( module ) ; 
13741417  let  content ; 
13751418  if  ( cached ?. source )  { 
@@ -1378,7 +1421,8 @@ Module._extensions['.js'] = function(module, filename) {
13781421  }  else  { 
13791422    content  =  fs . readFileSync ( filename ,  'utf8' ) ; 
13801423  } 
1381-   if  ( StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
1424+   if  ( ! getOptionValue ( '--experimental-require-module' )  && 
1425+       StringPrototypeEndsWith ( filename ,  '.js' ) )  { 
13821426    const  pkg  =  packageJsonReader . getNearestParentPackageJSON ( filename ) ; 
13831427    // Function require shouldn't be used in ES modules. 
13841428    if  ( pkg ?. data . type  ===  'module' )  { 
@@ -1414,7 +1458,8 @@ Module._extensions['.js'] = function(module, filename) {
14141458      throw  err ; 
14151459    } 
14161460  } 
1417-   module . _compile ( content ,  filename ) ; 
1461+ 
1462+   module . _compile ( content ,  filename ,  false ) ; 
14181463} ; 
14191464
14201465/** 
0 commit comments