Skip to content

Commit 898396a

Browse files
committedOct 8, 2024
module: do not warn when require(esm) comes from node_modules
Some packages have been using try-catch to load require(esm) in environments that are available. In 23, where require(esm) is unflagged, we emit an experimental warning when require() is used to load ESM. To backport require(esm) to older LTS releases, however, this could break existing CLI output. To reduce the disruption for LTS, on older release lines, this commit is applied to skip the warning if require(esm) comes from node_modules. This warning will be eventually removed when require(esm) becomes stable.
1 parent 76a2fa8 commit 898396a

File tree

11 files changed

+101
-2
lines changed

11 files changed

+101
-2
lines changed
 

‎lib/internal/modules/cjs/loader.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ const { pathToFileURL, fileURLToPath, isURL } = require('internal/url');
124124
const {
125125
pendingDeprecate,
126126
emitExperimentalWarning,
127+
isInsideNodeModules,
128+
isUnderNodeModules,
127129
kEmptyObject,
128130
setOwnProperty,
129131
getLazy,
@@ -1350,6 +1352,7 @@ let resolvedArgv;
13501352
let hasPausedEntry = false;
13511353
/** @type {import('vm').Script} */
13521354

1355+
let emittedRequireModuleWarning = false;
13531356
/**
13541357
* Resolve and evaluate it synchronously as ESM if it's ESM.
13551358
* @param {Module} mod CJS module instance
@@ -1373,11 +1376,27 @@ function loadESMFromCJS(mod, filename) {
13731376
// ESM won't be accessible via process.mainModule.
13741377
setOwnProperty(process, 'mainModule', undefined);
13751378
} else {
1376-
emitExperimentalWarning('Support for loading ES Module in require()');
1379+
const parent = mod[kModuleParent];
1380+
if (!emittedRequireModuleWarning) {
1381+
let shouldEmitWarning = false;
1382+
// Check if the require() comes from node_modules.
1383+
if (parent) {
1384+
shouldEmitWarning = !isUnderNodeModules(parent.filename)
1385+
} else if (mod[kIsCachedByESMLoader]) {
1386+
// It comes from the require() built for `import cjs` and doesn't have a parent recorded
1387+
// in the CJS module instance. Inspect the stack trace to see if the require()
1388+
// comes from node_modules.
1389+
shouldEmitWarning = !isInsideNodeModules();
1390+
}
1391+
if (shouldEmitWarning) {
1392+
emitExperimentalWarning('Support for loading ES Module in require()');
1393+
emittedRequireModuleWarning = true;
1394+
}
1395+
}
13771396
const {
13781397
wrap,
13791398
namespace,
1380-
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, mod[kModuleParent]);
1399+
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, parent);
13811400
// Tooling in the ecosystem have been using the __esModule property to recognize
13821401
// transpiled ESM in consuming code. For example, a 'log' package written in ESM:
13831402
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
// This checks the experimental warning for require(esm) is disabled when the
4+
// require() comes from node_modules.
5+
require('../common');
6+
const { spawnSyncAndAssert } = require('../common/child_process');
7+
const fixtures = require('../common/fixtures');
8+
9+
const warningRE = /ExperimentalWarning: Support for loading ES Module in require\(\)/;
10+
11+
// The fixtures are placed in a directory that includes "node_modules" in its name
12+
// to check false negatives.
13+
14+
// require() in non-node_modules -> esm in node_modules should warn.
15+
spawnSyncAndAssert(
16+
process.execPath,
17+
[fixtures.path('es-modules', 'test_node_modules', 'require-esm.js')],
18+
{
19+
trim: true,
20+
stderr: warningRE,
21+
stdout: 'world',
22+
}
23+
);
24+
25+
// require() in non-node_modules -> require() in node_modules -> esm in node_modules
26+
// should not warn.
27+
spawnSyncAndAssert(
28+
process.execPath,
29+
[fixtures.path('es-modules', 'test_node_modules', 'require-require-esm.js')],
30+
{
31+
trim: true,
32+
stderr: '',
33+
stdout: 'world',
34+
}
35+
);
36+
37+
// import in non-node_modules -> require() in node_modules -> esm in node_modules
38+
// should not warn.
39+
spawnSyncAndAssert(
40+
process.execPath,
41+
[fixtures.path('es-modules', 'test_node_modules', 'import-require-esm.mjs')],
42+
{
43+
trim: true,
44+
stderr: '',
45+
stdout: 'world',
46+
}
47+
);
48+
49+
// import in non-node_modules -> import in node_modules ->
50+
// require() in node_modules -> esm in node_modules should not warn.
51+
spawnSyncAndAssert(
52+
process.execPath,
53+
[fixtures.path('es-modules', 'test_node_modules', 'import-import-require-esm.mjs')],
54+
{
55+
trim: true,
56+
stderr: '',
57+
stdout: 'world',
58+
}
59+
);

‎test/fixtures/es-modules/test_node_modules/import-import-require-esm.mjs

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/import-require-esm.mjs

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/node_modules/esm/index.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/node_modules/esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/node_modules/import-require-esm/index.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/node_modules/import-require-esm/package.json

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/node_modules/require-esm/index.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/require-esm.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/es-modules/test_node_modules/require-require-esm.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)