@@ -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,
@@ -326,7 +332,8 @@ function Module(id = '', parent) {
326332 this . id = id ;
327333 this . path = path . dirname ( id ) ;
328334 setOwnProperty ( this , 'exports' , { } ) ;
329- this [ kModuleParent ] = parent ;
335+ this [ kFirstModuleParent ] = parent ;
336+ this [ kLastModuleParent ] = parent ;
330337 updateChildren ( parent , this , false ) ;
331338 this . filename = null ;
332339 this . loaded = false ;
@@ -408,7 +415,7 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
408415 * @returns {object }
409416 */
410417function getModuleParent ( ) {
411- return this [ kModuleParent ] ;
418+ return this [ kFirstModuleParent ] ;
412419}
413420
414421/**
@@ -418,7 +425,7 @@ function getModuleParent() {
418425 * @returns {void }
419426 */
420427function setModuleParent ( value ) {
421- this [ kModuleParent ] = value ;
428+ this [ kFirstModuleParent ] = value ;
422429}
423430
424431let debug = debuglog ( 'module' , ( fn ) => {
@@ -998,7 +1005,7 @@ function getExportsForCircularRequire(module) {
9981005 const requiredESM = module [ kRequiredModuleSymbol ] ;
9991006 if ( requiredESM && requiredESM . getStatus ( ) !== kEvaluated ) {
10001007 let message = `Cannot require() ES Module ${ module . id } in a cycle.` ;
1001- const parent = module [ kModuleParent ] ;
1008+ const parent = module [ kLastModuleParent ] ;
10021009 if ( parent ) {
10031010 message += ` (from ${ parent . filename } )` ;
10041011 }
@@ -1279,6 +1286,8 @@ Module._load = function(request, parent, isMain) {
12791286 // load hooks for the module keyed by the (potentially customized) filename.
12801287 module [ kURL ] = url ;
12811288 module [ kFormat ] = format ;
1289+ } else {
1290+ module [ kLastModuleParent ] = parent ;
12821291 }
12831292
12841293 if ( parent !== undefined ) {
@@ -1398,7 +1407,8 @@ Module._resolveFilename = function(request, parent, isMain, options) {
13981407 const requireStack = [ ] ;
13991408 for ( let cursor = parent ;
14001409 cursor ;
1401- cursor = cursor [ kModuleParent ] ) {
1410+ // TODO(joyeecheung): it makes more sense to use kLastModuleParent here.
1411+ cursor = cursor [ kFirstModuleParent ] ) {
14021412 ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
14031413 }
14041414 let message = `Cannot find module '${ request } '` ;
@@ -1515,7 +1525,7 @@ function loadESMFromCJS(mod, filename, format, source) {
15151525 // ESM won't be accessible via process.mainModule.
15161526 setOwnProperty ( process , 'mainModule' , undefined ) ;
15171527 } else {
1518- const parent = mod [ kModuleParent ] ;
1528+ const parent = mod [ kLastModuleParent ] ;
15191529
15201530 requireModuleWarningMode ??= getOptionValue ( '--trace-require-module' ) ;
15211531 if ( requireModuleWarningMode ) {
@@ -1565,54 +1575,66 @@ function loadESMFromCJS(mod, filename, format, source) {
15651575 wrap,
15661576 namespace,
15671577 } = cascadedLoader . importSyncForRequire ( mod , filename , source , isMain , parent ) ;
1568- // Tooling in the ecosystem have been using the __esModule property to recognize
1569- // transpiled ESM in consuming code. For example, a 'log' package written in ESM:
1570- //
1571- // export default function log(val) { console.log(val); }
1572- //
1573- // Can be transpiled as:
1574- //
1575- // exports.__esModule = true;
1576- // exports.default = function log(val) { console.log(val); }
1577- //
1578- // The consuming code may be written like this in ESM:
1579- //
1580- // import log from 'log'
1581- //
1582- // Which gets transpiled to:
1583- //
1584- // const _mod = require('log');
1585- // const log = _mod.__esModule ? _mod.default : _mod;
1586- //
1587- // So to allow transpiled consuming code to recognize require()'d real ESM
1588- // as ESM and pick up the default exports, we add a __esModule property by
1589- // building a source text module facade for any module that has a default
1590- // export and add .__esModule = true to the exports. This maintains the
1591- // enumerability of the re-exported names and the live binding of the exports,
1592- // without incurring a non-trivial per-access overhead on the exports.
1593- //
1594- // The source of the facade is defined as a constant per-isolate property
1595- // required_module_default_facade_source_string, which looks like this
1596- //
1597- // export * from 'original';
1598- // export { default } from 'original';
1599- // export const __esModule = true;
1600- //
1601- // And the 'original' module request is always resolved by
1602- // createRequiredModuleFacade() to `wrap` which is a ModuleWrap wrapping
1603- // over the original module.
1604-
1605- // We don't do this to modules that are marked as CJS ESM or that
1606- // don't have default exports to avoid the unnecessary overhead.
1607- // If __esModule is already defined, we will also skip the extension
1608- // to allow users to override it.
1609- if ( ObjectHasOwn ( namespace , 'module.exports' ) ) {
1610- mod . exports = namespace [ 'module.exports' ] ;
1611- } else if ( ! ObjectHasOwn ( namespace , 'default' ) || ObjectHasOwn ( namespace , '__esModule' ) ) {
1612- mod . exports = namespace ;
1613- } else {
1614- mod . exports = createRequiredModuleFacade ( wrap ) ;
1615- }
1578+
1579+ populateCJSExportsFromESM ( mod , wrap , namespace ) ;
1580+ }
1581+ }
1582+
1583+ /**
1584+ * Populate the exports of a CJS module entry from an ESM module's namespace object for
1585+ * require(esm).
1586+ * @param {Module } mod CJS module instance
1587+ * @param {ModuleWrap } wrap ESM ModuleWrap instance.
1588+ * @param {object } namespace The ESM namespace object.
1589+ */
1590+ function populateCJSExportsFromESM ( mod , wrap , namespace ) {
1591+ // Tooling in the ecosystem have been using the __esModule property to recognize
1592+ // transpiled ESM in consuming code. For example, a 'log' package written in ESM:
1593+ //
1594+ // export default function log(val) { console.log(val); }
1595+ //
1596+ // Can be transpiled as:
1597+ //
1598+ // exports.__esModule = true;
1599+ // exports.default = function log(val) { console.log(val); }
1600+ //
1601+ // The consuming code may be written like this in ESM:
1602+ //
1603+ // import log from 'log'
1604+ //
1605+ // Which gets transpiled to:
1606+ //
1607+ // const _mod = require('log');
1608+ // const log = _mod.__esModule ? _mod.default : _mod;
1609+ //
1610+ // So to allow transpiled consuming code to recognize require()'d real ESM
1611+ // as ESM and pick up the default exports, we add a __esModule property by
1612+ // building a source text module facade for any module that has a default
1613+ // export and add .__esModule = true to the exports. This maintains the
1614+ // enumerability of the re-exported names and the live binding of the exports,
1615+ // without incurring a non-trivial per-access overhead on the exports.
1616+ //
1617+ // The source of the facade is defined as a constant per-isolate property
1618+ // required_module_default_facade_source_string, which looks like this
1619+ //
1620+ // export * from 'original';
1621+ // export { default } from 'original';
1622+ // export const __esModule = true;
1623+ //
1624+ // And the 'original' module request is always resolved by
1625+ // createRequiredModuleFacade() to `wrap` which is a ModuleWrap wrapping
1626+ // over the original module.
1627+
1628+ // We don't do this to modules that are marked as CJS ESM or that
1629+ // don't have default exports to avoid the unnecessary overhead.
1630+ // If __esModule is already defined, we will also skip the extension
1631+ // to allow users to override it.
1632+ if ( ObjectHasOwn ( namespace , 'module.exports' ) ) {
1633+ mod . exports = namespace [ 'module.exports' ] ;
1634+ } else if ( ! ObjectHasOwn ( namespace , 'default' ) || ObjectHasOwn ( namespace , '__esModule' ) ) {
1635+ mod . exports = namespace ;
1636+ } else {
1637+ mod . exports = createRequiredModuleFacade ( wrap ) ;
16161638 }
16171639}
16181640
@@ -1805,7 +1827,7 @@ function reconstructErrorStack(err, parentPath, parentSource) {
18051827 */
18061828function getRequireESMError ( mod , pkg , content , filename ) {
18071829 // This is an error path because `require` of a `.js` file in a `"type": "module"` scope is not allowed.
1808- const parent = mod [ kModuleParent ] ;
1830+ const parent = mod [ kFirstModuleParent ] ;
18091831 const parentPath = parent ?. filename ;
18101832 const packageJsonPath = pkg ?. path ;
18111833 const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments