Skip to content

Commit 3d0afe0

Browse files
committed
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 b05c71e commit 3d0afe0

File tree

11 files changed

+100
-2
lines changed

11 files changed

+100
-2
lines changed

β€Žlib/internal/modules/cjs/loader.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ const { pathToFileURL, fileURLToPath, isURL } = require('internal/url');
124124
const {
125125
pendingDeprecate,
126126
emitExperimentalWarning,
127+
isInsideNodeModules,
127128
isUnderNodeModules,
128129
kEmptyObject,
129130
setOwnProperty,
@@ -1351,6 +1352,7 @@ let resolvedArgv;
13511352
let hasPausedEntry = false;
13521353
/** @type {import('vm').Script} */
13531354

1355+
let emittedRequireModuleWarning = false;
13541356
/**
13551357
* Resolve and evaluate it synchronously as ESM if it's ESM.
13561358
* @param {Module} mod CJS module instance
@@ -1374,11 +1376,27 @@ function loadESMFromCJS(mod, filename) {
13741376
// ESM won't be accessible via process.mainModule.
13751377
setOwnProperty(process, 'mainModule', undefined);
13761378
} else {
1377-
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+
}
13781396
const {
13791397
wrap,
13801398
namespace,
1381-
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, mod[kModuleParent]);
1399+
} = cascadedLoader.importSyncForRequire(mod, filename, source, isMain, parent);
13821400
// Tooling in the ecosystem have been using the __esModule property to recognize
13831401
// transpiled ESM in consuming code. For example, a 'log' package written in ESM:
13841402
//
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)