@@ -69,7 +69,8 @@ const {
6969 module_export_names_private_symbol,
7070 module_circular_visited_private_symbol,
7171 module_export_private_symbol,
72- module_parent_private_symbol,
72+ module_first_parent_private_symbol,
73+ module_last_parent_private_symbol,
7374 } ,
7475 isInsideNodeModules,
7576} = internalBinding ( 'util' ) ;
@@ -94,9 +95,13 @@ const kModuleCircularVisited = module_circular_visited_private_symbol;
9495 */
9596const kModuleExport = module_export_private_symbol ;
9697/**
97- * {@link Module } parent module.
98+ * {@link Module } The first parent module that loads a module with require() .
9899 */
99- const kModuleParent = module_parent_private_symbol ;
100+ const kFirstModuleParent = module_first_parent_private_symbol ;
101+ /**
102+ * {@link Module } The last parent module that loads a module with require().
103+ */
104+ const kLastModuleParent = module_last_parent_private_symbol ;
100105
101106const kIsMainSymbol = Symbol ( 'kIsMainSymbol' ) ;
102107const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
@@ -117,6 +122,7 @@ module.exports = {
117122 findLongestRegisteredExtension,
118123 resolveForCJSWithHooks,
119124 loadSourceForCJSWithHooks : loadSource ,
125+ populateCJSExportsFromESM,
120126 wrapSafe,
121127 wrapModuleLoad,
122128 kIsMainSymbol,
@@ -320,7 +326,8 @@ function Module(id = '', parent) {
320326 this . id = id ;
321327 this . path = path . dirname ( id ) ;
322328 setOwnProperty ( this , 'exports' , { } ) ;
323- this [ kModuleParent ] = parent ;
329+ this [ kFirstModuleParent ] = parent ;
330+ this [ kLastModuleParent ] = parent ;
324331 updateChildren ( parent , this , false ) ;
325332 this . filename = null ;
326333 this . loaded = false ;
@@ -400,7 +407,7 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
400407 * @this {Module}
401408 */
402409function getModuleParent ( ) {
403- return this [ kModuleParent ] ;
410+ return this [ kFirstModuleParent ] ;
404411}
405412
406413/**
@@ -409,7 +416,7 @@ function getModuleParent() {
409416 * @param {Module } value
410417 */
411418function setModuleParent ( value ) {
412- this [ kModuleParent ] = value ;
419+ this [ kFirstModuleParent ] = value ;
413420}
414421
415422let debug = debuglog ( 'module' , ( fn ) => {
@@ -972,7 +979,7 @@ function getExportsForCircularRequire(module) {
972979 const requiredESM = module [ kRequiredModuleSymbol ] ;
973980 if ( requiredESM && requiredESM . getStatus ( ) !== kEvaluated ) {
974981 let message = `Cannot require() ES Module ${ module . id } in a cycle.` ;
975- const parent = module [ kModuleParent ] ;
982+ const parent = module [ kLastModuleParent ] ;
976983 if ( parent ) {
977984 message += ` (from ${ parent . filename } )` ;
978985 }
@@ -1252,6 +1259,8 @@ Module._load = function(request, parent, isMain) {
12521259 // load hooks for the module keyed by the (potentially customized) filename.
12531260 module [ kURL ] = url ;
12541261 module [ kFormat ] = format ;
1262+ } else {
1263+ module [ kLastModuleParent ] = parent ;
12551264 }
12561265
12571266 if ( parent !== undefined ) {
@@ -1371,7 +1380,8 @@ Module._resolveFilename = function(request, parent, isMain, options) {
13711380 const requireStack = [ ] ;
13721381 for ( let cursor = parent ;
13731382 cursor ;
1374- cursor = cursor [ kModuleParent ] ) {
1383+ // TODO(joyeecheung): it makes more sense to use kLastModuleParent here.
1384+ cursor = cursor [ kFirstModuleParent ] ) {
13751385 ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
13761386 }
13771387 let message = `Cannot find module '${ request } '` ;
@@ -1485,7 +1495,7 @@ function loadESMFromCJS(mod, filename, format, source) {
14851495 // ESM won't be accessible via process.mainModule.
14861496 setOwnProperty ( process , 'mainModule' , undefined ) ;
14871497 } else {
1488- const parent = mod [ kModuleParent ] ;
1498+ const parent = mod [ kLastModuleParent ] ;
14891499
14901500 requireModuleWarningMode ??= getOptionValue ( '--trace-require-module' ) ;
14911501 if ( requireModuleWarningMode ) {
@@ -1534,54 +1544,66 @@ function loadESMFromCJS(mod, filename, format, source) {
15341544 wrap,
15351545 namespace,
15361546 } = cascadedLoader . importSyncForRequire ( mod , filename , source , isMain , parent ) ;
1537- // Tooling in the ecosystem have been using the __esModule property to recognize
1538- // transpiled ESM in consuming code. For example, a 'log' package written in ESM:
1539- //
1540- // export default function log(val) { console.log(val); }
1541- //
1542- // Can be transpiled as:
1543- //
1544- // exports.__esModule = true;
1545- // exports.default = function log(val) { console.log(val); }
1546- //
1547- // The consuming code may be written like this in ESM:
1548- //
1549- // import log from 'log'
1550- //
1551- // Which gets transpiled to:
1552- //
1553- // const _mod = require('log');
1554- // const log = _mod.__esModule ? _mod.default : _mod;
1555- //
1556- // So to allow transpiled consuming code to recognize require()'d real ESM
1557- // as ESM and pick up the default exports, we add a __esModule property by
1558- // building a source text module facade for any module that has a default
1559- // export and add .__esModule = true to the exports. This maintains the
1560- // enumerability of the re-exported names and the live binding of the exports,
1561- // without incurring a non-trivial per-access overhead on the exports.
1562- //
1563- // The source of the facade is defined as a constant per-isolate property
1564- // required_module_default_facade_source_string, which looks like this
1565- //
1566- // export * from 'original';
1567- // export { default } from 'original';
1568- // export const __esModule = true;
1569- //
1570- // And the 'original' module request is always resolved by
1571- // createRequiredModuleFacade() to `wrap` which is a ModuleWrap wrapping
1572- // over the original module.
1573-
1574- // We don't do this to modules that are marked as CJS ESM or that
1575- // don't have default exports to avoid the unnecessary overhead.
1576- // If __esModule is already defined, we will also skip the extension
1577- // to allow users to override it.
1578- if ( ObjectHasOwn ( namespace , 'module.exports' ) ) {
1579- mod . exports = namespace [ 'module.exports' ] ;
1580- } else if ( ! ObjectHasOwn ( namespace , 'default' ) || ObjectHasOwn ( namespace , '__esModule' ) ) {
1581- mod . exports = namespace ;
1582- } else {
1583- mod . exports = createRequiredModuleFacade ( wrap ) ;
1584- }
1547+
1548+ populateCJSExportsFromESM ( mod , wrap , namespace ) ;
1549+ }
1550+ }
1551+
1552+ /**
1553+ * Populate the exports of a CJS module entry from an ESM module's namespace object for
1554+ * require(esm).
1555+ * @param {Module } mod CJS module instance
1556+ * @param {ModuleWrap } wrap ESM ModuleWrap instance.
1557+ * @param {object } namespace The ESM namespace object.
1558+ */
1559+ function populateCJSExportsFromESM ( mod , wrap , namespace ) {
1560+ // Tooling in the ecosystem have been using the __esModule property to recognize
1561+ // transpiled ESM in consuming code. For example, a 'log' package written in ESM:
1562+ //
1563+ // export default function log(val) { console.log(val); }
1564+ //
1565+ // Can be transpiled as:
1566+ //
1567+ // exports.__esModule = true;
1568+ // exports.default = function log(val) { console.log(val); }
1569+ //
1570+ // The consuming code may be written like this in ESM:
1571+ //
1572+ // import log from 'log'
1573+ //
1574+ // Which gets transpiled to:
1575+ //
1576+ // const _mod = require('log');
1577+ // const log = _mod.__esModule ? _mod.default : _mod;
1578+ //
1579+ // So to allow transpiled consuming code to recognize require()'d real ESM
1580+ // as ESM and pick up the default exports, we add a __esModule property by
1581+ // building a source text module facade for any module that has a default
1582+ // export and add .__esModule = true to the exports. This maintains the
1583+ // enumerability of the re-exported names and the live binding of the exports,
1584+ // without incurring a non-trivial per-access overhead on the exports.
1585+ //
1586+ // The source of the facade is defined as a constant per-isolate property
1587+ // required_module_default_facade_source_string, which looks like this
1588+ //
1589+ // export * from 'original';
1590+ // export { default } from 'original';
1591+ // export const __esModule = true;
1592+ //
1593+ // And the 'original' module request is always resolved by
1594+ // createRequiredModuleFacade() to `wrap` which is a ModuleWrap wrapping
1595+ // over the original module.
1596+
1597+ // We don't do this to modules that are marked as CJS ESM or that
1598+ // don't have default exports to avoid the unnecessary overhead.
1599+ // If __esModule is already defined, we will also skip the extension
1600+ // to allow users to override it.
1601+ if ( ObjectHasOwn ( namespace , 'module.exports' ) ) {
1602+ mod . exports = namespace [ 'module.exports' ] ;
1603+ } else if ( ! ObjectHasOwn ( namespace , 'default' ) || ObjectHasOwn ( namespace , '__esModule' ) ) {
1604+ mod . exports = namespace ;
1605+ } else {
1606+ mod . exports = createRequiredModuleFacade ( wrap ) ;
15851607 }
15861608}
15871609
@@ -1772,7 +1794,7 @@ function reconstructErrorStack(err, parentPath, parentSource) {
17721794 */
17731795function getRequireESMError ( mod , pkg , content , filename ) {
17741796 // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1775- const parent = mod [ kModuleParent ] ;
1797+ const parent = mod [ kFirstModuleParent ] ;
17761798 const parentPath = parent ?. filename ;
17771799 const packageJsonPath = pkg ?. path ;
17781800 const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments