Skip to content

Commit 5d78d74

Browse files
committed
module: include module information in require(esm) warning
When emitting the experimental warning for `require(esm)`, include information about the parent module and the module being require()-d to help users locate and update them. PR-URL: nodejs#55397 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 714e88e commit 5d78d74

File tree

4 files changed

+41
-12
lines changed

4 files changed

+41
-12
lines changed

lib/internal/modules/cjs/loader.js

+22-2
Original file line numberDiff line numberDiff line change
@@ -1340,11 +1340,31 @@ function loadESMFromCJS(mod, filename) {
13401340
// ESM won't be accessible via process.mainModule.
13411341
setOwnProperty(process, 'mainModule', undefined);
13421342
} else {
1343-
emitExperimentalWarning('Support for loading ES Module in require()');
1343+
const parent = mod[kModuleParent];
1344+
let messagePrefix;
1345+
if (parent) {
1346+
// In the case of the module calling `require()`, it's more useful to know its absolute path.
1347+
let from = parent.filename || parent.id;
1348+
// In the case of the module being require()d, it's more useful to know the id passed into require().
1349+
const to = mod.id || mod.filename;
1350+
if (from === 'internal/preload') {
1351+
from = '--require';
1352+
} else if (from === '<repl>') {
1353+
from = 'The REPL';
1354+
} else if (from === '.') {
1355+
from = 'The entry point';
1356+
} else {
1357+
from &&= `CommonJS module ${from}`;
1358+
}
1359+
if (from && to) {
1360+
messagePrefix = `${from} is loading ES Module ${to} using require().\n`;
1361+
}
1362+
}
1363+
emitExperimentalWarning('Support for loading ES Module in require()', messagePrefix);
13441364
const {
13451365
wrap,
13461366
namespace,
1347-
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, mod[kModuleParent]);
1367+
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, parent);
13481368
// Tooling in the ecosystem have been using the __esModule property to recognize
13491369
// transpiled ESM in consuming code. For example, a 'log' package written in ESM:
13501370
//

lib/internal/util.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,13 @@ function slowCases(enc) {
255255
}
256256
}
257257

258-
function emitExperimentalWarning(feature) {
258+
function emitExperimentalWarning(feature, messagePrefix) {
259259
if (experimentalWarnings.has(feature)) return;
260-
const msg = `${feature} is an experimental feature and might change at any time`;
261260
experimentalWarnings.add(feature);
261+
let msg = `${feature} is an experimental feature and might change at any time`;
262+
if (messagePrefix) {
263+
msg = messagePrefix + msg;
264+
}
262265
process.emitWarning(msg, 'ExperimentalWarning');
263266
}
264267

test/es-module/test-require-module-preload.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ require('../common');
44
const { spawnSyncAndAssert } = require('../common/child_process');
55
const { fixturesDir } = require('../common/fixtures');
66

7-
const warningRE = /ExperimentalWarning: Support for loading ES Module in require/;
87
function testPreload(preloadFlag) {
98
// The warning is only emitted when ESM is loaded by --require.
10-
const stderr = preloadFlag !== '--import' ? warningRE : undefined;
11-
9+
const isRequire = preloadFlag === '--require';
1210
// Test named exports.
1311
{
1412
spawnSyncAndAssert(
@@ -24,7 +22,8 @@ function testPreload(preloadFlag) {
2422
},
2523
{
2624
stdout: 'A',
27-
stderr,
25+
stderr: isRequire ?
26+
/ExperimentalWarning: --require is loading ES Module .*module-named-exports\.mjs using require/ : undefined,
2827
trim: true,
2928
}
3029
);
@@ -44,7 +43,8 @@ function testPreload(preloadFlag) {
4443
cwd: fixturesDir
4544
},
4645
{
47-
stderr,
46+
stderr: isRequire ?
47+
/ExperimentalWarning: --require is loading ES Module .*import-esm\.mjs using require/ : undefined,
4848
stdout: /^world\s+A$/,
4949
trim: true,
5050
}
@@ -66,7 +66,8 @@ function testPreload(preloadFlag) {
6666
},
6767
{
6868
stdout: /^ok\s+A$/,
69-
stderr,
69+
stderr: isRequire ?
70+
/ExperimentalWarning: --require is loading ES Module .*cjs-exports\.mjs using require/ : undefined,
7071
trim: true,
7172
}
7273
);
@@ -89,7 +90,8 @@ function testPreload(preloadFlag) {
8990
},
9091
{
9192
stdout: /^world\s+A$/,
92-
stderr,
93+
stderr: isRequire ?
94+
/ExperimentalWarning: --require is loading ES Module .*require-cjs\.mjs using require/ : undefined,
9395
trim: true,
9496
}
9597
);
@@ -115,7 +117,7 @@ testPreload('--import');
115117
},
116118
{
117119
stdout: /^package-type-module\s+A$/,
118-
stderr: warningRE,
120+
stderr: /ExperimentalWarning: --require is loading ES Module .*package-type-module[\\/]index\.js using require/,
119121
trim: true,
120122
}
121123
);

test/es-module/test-require-module.js

+4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33

44
const common = require('../common');
55
const assert = require('assert');
6+
const path = require('path');
67

8+
// Only the first load will trigger the warning.
79
common.expectWarning(
810
'ExperimentalWarning',
11+
`CommonJS module ${__filename} is loading ES Module ` +
12+
`${path.resolve(__dirname, '../fixtures/es-module-loaders/module-named-exports.mjs')} using require().\n` +
913
'Support for loading ES Module in require() is an experimental feature ' +
1014
'and might change at any time'
1115
);

0 commit comments

Comments
 (0)