@@ -69,7 +69,8 @@ const {
69
69
module_export_names_private_symbol,
70
70
module_circular_visited_private_symbol,
71
71
module_export_private_symbol,
72
- module_parent_private_symbol,
72
+ module_first_parent_private_symbol,
73
+ module_last_parent_private_symbol,
73
74
} ,
74
75
isInsideNodeModules,
75
76
} = internalBinding ( 'util' ) ;
@@ -94,9 +95,13 @@ const kModuleCircularVisited = module_circular_visited_private_symbol;
94
95
*/
95
96
const kModuleExport = module_export_private_symbol ;
96
97
/**
97
- * {@link Module } parent module.
98
+ * {@link Module } The first parent module that loads a module with require() .
98
99
*/
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 ;
100
105
101
106
const kIsMainSymbol = Symbol ( 'kIsMainSymbol' ) ;
102
107
const kIsCachedByESMLoader = Symbol ( 'kIsCachedByESMLoader' ) ;
@@ -117,6 +122,7 @@ module.exports = {
117
122
findLongestRegisteredExtension,
118
123
resolveForCJSWithHooks,
119
124
loadSourceForCJSWithHooks : loadSource ,
125
+ populateCJSExportsFromESM,
120
126
wrapSafe,
121
127
wrapModuleLoad,
122
128
kIsMainSymbol,
@@ -326,7 +332,8 @@ function Module(id = '', parent) {
326
332
this . id = id ;
327
333
this . path = path . dirname ( id ) ;
328
334
setOwnProperty ( this , 'exports' , { } ) ;
329
- this [ kModuleParent ] = parent ;
335
+ this [ kFirstModuleParent ] = parent ;
336
+ this [ kLastModuleParent ] = parent ;
330
337
updateChildren ( parent , this , false ) ;
331
338
this . filename = null ;
332
339
this . loaded = false ;
@@ -408,7 +415,7 @@ ObjectDefineProperty(BuiltinModule.prototype, 'isPreloading', isPreloadingDesc);
408
415
* @returns {object }
409
416
*/
410
417
function getModuleParent ( ) {
411
- return this [ kModuleParent ] ;
418
+ return this [ kFirstModuleParent ] ;
412
419
}
413
420
414
421
/**
@@ -418,7 +425,7 @@ function getModuleParent() {
418
425
* @returns {void }
419
426
*/
420
427
function setModuleParent ( value ) {
421
- this [ kModuleParent ] = value ;
428
+ this [ kFirstModuleParent ] = value ;
422
429
}
423
430
424
431
let debug = debuglog ( 'module' , ( fn ) => {
@@ -998,7 +1005,7 @@ function getExportsForCircularRequire(module) {
998
1005
const requiredESM = module [ kRequiredModuleSymbol ] ;
999
1006
if ( requiredESM && requiredESM . getStatus ( ) !== kEvaluated ) {
1000
1007
let message = `Cannot require() ES Module ${ module . id } in a cycle.` ;
1001
- const parent = module [ kModuleParent ] ;
1008
+ const parent = module [ kLastModuleParent ] ;
1002
1009
if ( parent ) {
1003
1010
message += ` (from ${ parent . filename } )` ;
1004
1011
}
@@ -1279,6 +1286,8 @@ Module._load = function(request, parent, isMain) {
1279
1286
// load hooks for the module keyed by the (potentially customized) filename.
1280
1287
module [ kURL ] = url ;
1281
1288
module [ kFormat ] = format ;
1289
+ } else {
1290
+ module [ kLastModuleParent ] = parent ;
1282
1291
}
1283
1292
1284
1293
if ( parent !== undefined ) {
@@ -1398,7 +1407,8 @@ Module._resolveFilename = function(request, parent, isMain, options) {
1398
1407
const requireStack = [ ] ;
1399
1408
for ( let cursor = parent ;
1400
1409
cursor ;
1401
- cursor = cursor [ kModuleParent ] ) {
1410
+ // TODO(joyeecheung): it makes more sense to use kLastModuleParent here.
1411
+ cursor = cursor [ kFirstModuleParent ] ) {
1402
1412
ArrayPrototypePush ( requireStack , cursor . filename || cursor . id ) ;
1403
1413
}
1404
1414
let message = `Cannot find module '${ request } '` ;
@@ -1515,7 +1525,7 @@ function loadESMFromCJS(mod, filename, format, source) {
1515
1525
// ESM won't be accessible via process.mainModule.
1516
1526
setOwnProperty ( process , 'mainModule' , undefined ) ;
1517
1527
} else {
1518
- const parent = mod [ kModuleParent ] ;
1528
+ const parent = mod [ kLastModuleParent ] ;
1519
1529
1520
1530
requireModuleWarningMode ??= getOptionValue ( '--trace-require-module' ) ;
1521
1531
if ( requireModuleWarningMode ) {
@@ -1565,54 +1575,66 @@ function loadESMFromCJS(mod, filename, format, source) {
1565
1575
wrap,
1566
1576
namespace,
1567
1577
} = 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 ) ;
1616
1638
}
1617
1639
}
1618
1640
@@ -1805,7 +1827,7 @@ function reconstructErrorStack(err, parentPath, parentSource) {
1805
1827
*/
1806
1828
function getRequireESMError ( mod , pkg , content , filename ) {
1807
1829
// 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 ] ;
1809
1831
const parentPath = parent ?. filename ;
1810
1832
const packageJsonPath = pkg ?. path ;
1811
1833
const usesEsm = containsModuleSyntax ( content , filename ) ;
0 commit comments