@@ -60,6 +60,7 @@ const {
60
60
StringPrototypeSlice,
61
61
StringPrototypeSplit,
62
62
StringPrototypeStartsWith,
63
+ Symbol,
63
64
} = primordials ;
64
65
65
66
// Map used to store CJS parsing data.
@@ -107,7 +108,6 @@ const { safeGetenv } = internalBinding('credentials');
107
108
const {
108
109
privateSymbols : {
109
110
require_private_symbol,
110
- host_defined_option_symbol,
111
111
} ,
112
112
} = internalBinding ( 'util' ) ;
113
113
const {
@@ -161,6 +161,8 @@ let requireDepth = 0;
161
161
let isPreloading = false ;
162
162
let statCache = null ;
163
163
164
+ const is_main_symbol = Symbol ( 'is-main-module' ) ;
165
+
164
166
/**
165
167
* Our internal implementation of `require`.
166
168
* @param {Module } module Parent module of what is being required
@@ -271,6 +273,7 @@ function Module(id = '', parent) {
271
273
setOwnProperty ( this . __proto__ , 'require' , makeRequireFunction ( this , redirects ) ) ;
272
274
}
273
275
this [ require_private_symbol ] = internalRequire ;
276
+ this [ is_main_symbol ] = false ; // Set to true by the entry point handler.
274
277
}
275
278
276
279
/** @type {Record<string, Module> } */
@@ -396,6 +399,10 @@ function initializeCJS() {
396
399
// TODO(joyeecheung): deprecate this in favor of a proper hook?
397
400
Module . runMain =
398
401
require ( 'internal/modules/run_main' ) . executeUserEntryPoint ;
402
+
403
+ if ( getOptionValue ( '--experimental-require-module' ) ) {
404
+ Module . _extensions [ '.mjs' ] = loadESMFromCJS ;
405
+ }
399
406
}
400
407
401
408
// Given a module name, and a list of paths to test, returns the first
@@ -1010,6 +1017,7 @@ Module._load = function(request, parent, isMain) {
1010
1017
setOwnProperty ( process , 'mainModule' , module ) ;
1011
1018
setOwnProperty ( module . require , 'main' , process . mainModule ) ;
1012
1019
module . id = '.' ;
1020
+ module [ is_main_symbol ] = true ;
1013
1021
}
1014
1022
1015
1023
reportModuleToWatchMode ( filename ) ;
@@ -1270,46 +1278,58 @@ function wrapSafe(filename, content, cjsModuleInstance, codeCache) {
1270
1278
) ;
1271
1279
1272
1280
// 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 ) ;
1275
1284
}
1276
1285
1277
- return runScriptInThisContext ( script , true , false ) ;
1286
+ return {
1287
+ __proto__ : null ,
1288
+ function : runScriptInThisContext ( script , true , false ) ,
1289
+ sourceMapURL,
1290
+ retryAsESM : false ,
1291
+ } ;
1278
1292
}
1279
1293
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 ) ;
1290
1295
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
+ }
1295
1302
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 ) ;
1303
1306
}
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 ;
1304
1323
}
1305
1324
1306
1325
/**
1307
1326
* Run the file contents in the correct scope or sandbox. Expose the correct helper variables (`require`, `module`,
1308
1327
* `exports`) to the file. Returns exception, if any.
1309
1328
* @param {string } content The source code of the module
1310
1329
* @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.
1311
1331
*/
1312
- Module . prototype . _compile = function ( content , filename ) {
1332
+ Module . prototype . _compile = function ( content , filename , loadAsESM = false ) {
1313
1333
let moduleURL ;
1314
1334
let redirects ;
1315
1335
const manifest = policy ( ) ?. manifest ;
@@ -1319,8 +1339,21 @@ Module.prototype._compile = function(content, filename) {
1319
1339
manifest . assertIntegrity ( moduleURL , content ) ;
1320
1340
}
1321
1341
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
+ }
1323
1353
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.
1324
1357
let inspectorWrapper = null ;
1325
1358
if ( getOptionValue ( '--inspect-brk' ) && process . _eval == null ) {
1326
1359
if ( ! resolvedArgv ) {
@@ -1344,6 +1377,7 @@ Module.prototype._compile = function(content, filename) {
1344
1377
inspectorWrapper = internalBinding ( 'inspector' ) . callAndPauseOnStart ;
1345
1378
}
1346
1379
}
1380
+
1347
1381
const dirname = path . dirname ( filename ) ;
1348
1382
const require = makeRequireFunction ( this , redirects ) ;
1349
1383
let result ;
@@ -1370,6 +1404,7 @@ Module.prototype._compile = function(content, filename) {
1370
1404
*/
1371
1405
Module . _extensions [ '.js' ] = function ( module , filename ) {
1372
1406
// If already analyzed the source, then it will be cached.
1407
+ // TODO(joyeecheung): pass as buffer.
1373
1408
const cached = cjsParseCache . get ( module ) ;
1374
1409
let content ;
1375
1410
if ( cached ?. source ) {
@@ -1378,7 +1413,8 @@ Module._extensions['.js'] = function(module, filename) {
1378
1413
} else {
1379
1414
content = fs . readFileSync ( filename , 'utf8' ) ;
1380
1415
}
1381
- if ( StringPrototypeEndsWith ( filename , '.js' ) ) {
1416
+ if ( ! getOptionValue ( '--experimental-require-module' ) &&
1417
+ StringPrototypeEndsWith ( filename , '.js' ) ) {
1382
1418
const pkg = packageJsonReader . getNearestParentPackageJSON ( filename ) ;
1383
1419
// Function require shouldn't be used in ES modules.
1384
1420
if ( pkg ?. data . type === 'module' ) {
@@ -1414,7 +1450,8 @@ Module._extensions['.js'] = function(module, filename) {
1414
1450
throw err ;
1415
1451
}
1416
1452
}
1417
- module . _compile ( content , filename ) ;
1453
+
1454
+ module . _compile ( content , filename , false ) ;
1418
1455
} ;
1419
1456
1420
1457
/**
0 commit comments