Skip to content

Commit 7af5b5d

Browse files
committed
module: unflag --experimental-require-module
This unflags --experimental-require-module so require(esm) can be used without the flag. For now, when require() actually encounters an ESM, it will still emit an experimental warning. To opt out of the feature, --no-experimental-require-module can be used. There are some tests specifically testing ERR_REQUIRE_ESM. Some of them are repurposed to test --no-experimental-require-module. Some of them are modified to just expect loading require(esm) to work, when it's appropriate.
1 parent 3c5ceff commit 7af5b5d

15 files changed

+67
-34
lines changed

lib/internal/modules/cjs/loader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,6 @@ function initializeCJS() {
437437
Module._extensions['.ts'] = loadTS;
438438
}
439439
if (getOptionValue('--experimental-require-module')) {
440-
emitExperimentalWarning('Support for loading ES Module in require()');
441440
Module._extensions['.mjs'] = loadESMFromCJS;
442441
if (tsEnabled) {
443442
Module._extensions['.mts'] = loadESMFromCJS;
@@ -1386,6 +1385,7 @@ function loadESMFromCJS(mod, filename) {
13861385
// ESM won't be accessible via process.mainModule.
13871386
setOwnProperty(process, 'mainModule', undefined);
13881387
} else {
1388+
emitExperimentalWarning('Support for loading ES Module in require()');
13891389
const {
13901390
wrap,
13911391
namespace,

lib/internal/modules/esm/load.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,6 @@ async function defaultLoad(url, context = kEmptyObject) {
131131

132132
validateAttributes(url, format, importAttributes);
133133

134-
// Use the synchronous commonjs translator which can deal with cycles.
135-
if (format === 'commonjs' && getOptionValue('--experimental-require-module')) {
136-
format = 'commonjs-sync';
137-
}
138-
139134
if (getOptionValue('--experimental-strip-types') &&
140135
(format === 'module-typescript' || format === 'commonjs-typescript') &&
141136
isUnderNodeModules(url)) {
@@ -191,11 +186,6 @@ function defaultLoadSync(url, context = kEmptyObject) {
191186

192187
validateAttributes(url, format, importAttributes);
193188

194-
// Use the synchronous commonjs translator which can deal with cycles.
195-
if (format === 'commonjs' && getOptionValue('--experimental-require-module')) {
196-
format = 'commonjs-sync';
197-
}
198-
199189
return {
200190
__proto__: null,
201191
format,

lib/internal/modules/esm/loader.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,15 @@ class ModuleLoader {
372372

373373
defaultLoadSync ??= require('internal/modules/esm/load').defaultLoadSync;
374374
const loadResult = defaultLoadSync(url, { format, importAttributes });
375-
const {
376-
format: finalFormat,
377-
source,
378-
} = loadResult;
375+
376+
// Use the synchronous commonjs translator which can deal with cycles.
377+
const finalFormat = loadResult.format === 'commonjs' ? 'commonjs-sync' : loadResult.format;
379378

380379
if (finalFormat === 'wasm') {
381380
assert.fail('WASM is currently unsupported by require(esm)');
382381
}
383382

383+
const { source } = loadResult;
384384
const isMain = (parentURL === undefined);
385385
const wrap = this.#translate(url, finalFormat, source, isMain);
386386
assert(wrap instanceof ModuleWrap, `Translator used for require(${url}) should not be async`);

lib/internal/modules/esm/module_job.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ class ModuleJobSync extends ModuleJobBase {
361361
}
362362

363363
runSync() {
364+
// TODO(joyeecheung): add the error decoration logic from the async instantiate.
364365
this.module.instantiateSync();
365366
setHasStartedUserESMExecution();
366367
const namespace = this.module.evaluateSync();

src/node_options.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class EnvironmentOptions : public Options {
117117
std::vector<std::string> conditions;
118118
bool detect_module = true;
119119
bool print_required_tla = false;
120-
bool require_module = false;
120+
bool require_module = true;
121121
std::string dns_result_order;
122122
bool enable_source_maps = false;
123123
bool experimental_eventsource = false;

test/es-module/test-cjs-esm-warn.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Previously, this tested that require(esm) throws ERR_REQUIRE_ESM, which is no longer applicable
2+
// since require(esm) is now supported. The test has been repurposed to ensure that the old behavior
3+
// is preserved when the --no-experimental-require-module flag is used.
14
'use strict';
25

36
const { spawnPromisified } = require('../common');
@@ -22,7 +25,9 @@ describe('CJS ↔︎ ESM interop warnings', { concurrency: !process.env.TEST_PAR
2225
fixtures.path('/es-modules/package-type-module/cjs.js')
2326
);
2427
const basename = 'cjs.js';
25-
const { code, signal, stderr } = await spawnPromisified(execPath, [requiringCjsAsEsm]);
28+
const { code, signal, stderr } = await spawnPromisified(execPath, [
29+
'--no-experimental-require-module', requiringCjsAsEsm,
30+
]);
2631

2732
assert.ok(
2833
stderr.replaceAll('\r', '').includes(
@@ -48,7 +53,9 @@ describe('CJS ↔︎ ESM interop warnings', { concurrency: !process.env.TEST_PAR
4853
fixtures.path('/es-modules/package-type-module/esm.js')
4954
);
5055
const basename = 'esm.js';
51-
const { code, signal, stderr } = await spawnPromisified(execPath, [requiringEsm]);
56+
const { code, signal, stderr } = await spawnPromisified(execPath, [
57+
'--no-experimental-require-module', requiringEsm,
58+
]);
5259

5360
assert.ok(
5461
stderr.replace(/\r/g, '').includes(

test/es-module/test-esm-detect-ambiguous.mjs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,15 +402,16 @@ describe('Module syntax detection', { concurrency: !process.env.TEST_PARALLEL },
402402
});
403403
});
404404

405-
// Validate temporarily disabling `--abort-on-uncaught-exception`
406-
// while running `containsModuleSyntax`.
405+
// Checks the error caught during module detection does not trigger abort when
406+
// `--abort-on-uncaught-exception` is passed in (as that's a caught internal error).
407407
// Ref: https://github.com/nodejs/node/issues/50878
408408
describe('Wrapping a `require` of an ES module while using `--abort-on-uncaught-exception`', () => {
409409
it('should work', async () => {
410410
const { code, signal, stdout, stderr } = await spawnPromisified(process.execPath, [
411411
'--abort-on-uncaught-exception',
412+
'--no-warnings',
412413
'--eval',
413-
'assert.throws(() => require("./package-type-module/esm.js"), { code: "ERR_REQUIRE_ESM" })',
414+
'require("./package-type-module/esm.js")',
414415
], {
415416
cwd: fixtures.path('es-modules'),
416417
});

test/es-module/test-esm-loader-hooks.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ describe('Loader hooks', { concurrency: !process.env.TEST_PARALLEL }, () => {
774774

775775
describe('should use hooks', async () => {
776776
const { code, signal, stdout, stderr } = await spawnPromisified(process.execPath, [
777+
'--no-experimental-require-module',
777778
'--import',
778779
fixtures.fileURL('es-module-loaders/builtin-named-exports.mjs'),
779780
fixtures.path('es-modules/require-esm-throws-with-loaders.js'),
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Flags: --no-experimental-require-module
2+
// Previously, this tested that require(esm) throws ERR_REQUIRE_ESM, which is no longer applicable
3+
// since require(esm) is now supported. The test has been repurposed to ensure that the old behavior
4+
// is preserved when the --no-experimental-require-module flag is used.
5+
6+
'use strict';
7+
require('../common');
8+
const assert = require('assert');
9+
const { describe, it } = require('node:test');
10+
11+
describe('Errors related to ESM type field', () => {
12+
it('Should throw an error when loading CJS from a `type: "module"` package.', () => {
13+
assert.throws(() => require('../fixtures/es-modules/package-type-module/index.js'), {
14+
code: 'ERR_REQUIRE_ESM'
15+
});
16+
});
17+
});

test/es-module/test-esm-type-field-errors.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ describe('ESM type field errors', { concurrency: true }, () => {
5050
true,
5151
);
5252
});
53-
54-
it('--input-type=module disallowed for directories', () => {
55-
assert.throws(() => require('../fixtures/es-modules/package-type-module/index.js'), {
56-
code: 'ERR_REQUIRE_ESM'
57-
});
58-
});
5953
});
6054

6155
function expect(opt = '', inputFile, want, wantsError = false) {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
require('../common');
44
const { spawnSyncAndAssert } = require('../common/child_process');
55
const { fixturesDir } = require('../common/fixtures');
6-
const stderr = /ExperimentalWarning: Support for loading ES Module in require/;
76

7+
const warningRE = /ExperimentalWarning: Support for loading ES Module in require/;
88
function testPreload(preloadFlag) {
9+
// The warning is only emitted when ESM is loaded by --require.
10+
const stderr = preloadFlag !== '--import' ? warningRE : undefined;
11+
912
// Test named exports.
1013
{
1114
spawnSyncAndAssert(
@@ -112,7 +115,7 @@ testPreload('--import');
112115
},
113116
{
114117
stdout: /^package-type-module\s+A$/,
115-
stderr,
118+
stderr: warningRE,
116119
trim: true,
117120
}
118121
);

test/es-module/test-typescript-commonjs.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ test('execute a .cts file importing a .ts file export', async () => {
100100
test('execute a .cts file importing a .mts file export', async () => {
101101
const result = await spawnPromisified(process.execPath, [
102102
'--experimental-strip-types',
103+
'--no-experimental-require-module',
103104
fixtures.path('typescript/cts/test-require-mts-module.cts'),
104105
]);
105106

@@ -158,6 +159,7 @@ test('expect failure of a .ts file in node_modules', async () => {
158159
test('expect failure of a .cts requiring esm without default type module', async () => {
159160
const result = await spawnPromisified(process.execPath, [
160161
'--experimental-strip-types',
162+
'--no-experimental-require-module',
161163
fixtures.path('typescript/cts/test-mts-node_modules.cts'),
162164
]);
163165

test/es-module/test-typescript-module.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ test('execute an .mts file importing a .cts file', async () => {
6767
test('execute an .mts file with wrong default module', async () => {
6868
const result = await spawnPromisified(process.execPath, [
6969
'--experimental-strip-types',
70+
'--no-experimental-require-module',
7071
'--experimental-default-type=commonjs',
7172
fixtures.path('typescript/mts/test-import-module.mts'),
7273
]);
@@ -76,6 +77,18 @@ test('execute an .mts file with wrong default module', async () => {
7677
strictEqual(result.code, 1);
7778
});
7879

80+
test('execute an .mts file with wrong default module', async () => {
81+
const result = await spawnPromisified(process.execPath, [
82+
'--experimental-strip-types',
83+
'--experimental-require-module',
84+
'--experimental-default-type=commonjs',
85+
fixtures.path('typescript/mts/test-import-module.mts'),
86+
]);
87+
88+
match(result.stdout, /Hello, TypeScript!/);
89+
strictEqual(result.code, 0);
90+
});
91+
7992
test('execute an .mts file from node_modules', async () => {
8093
const result = await spawnPromisified(process.execPath, [
8194
'--experimental-strip-types',

test/es-module/test-typescript.mjs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ test('execute a TypeScript file with imports', async () => {
3232
const result = await spawnPromisified(process.execPath, [
3333
'--no-warnings',
3434
'--eval',
35-
`assert.throws(() => require(${JSON.stringify(fixtures.path('typescript/ts/test-import-fs.ts'))}), {code: 'ERR_REQUIRE_ESM'})`,
35+
`require(${JSON.stringify(fixtures.path('typescript/ts/test-import-fs.ts'))})`,
3636
]);
3737

3838
strictEqual(result.stderr, '');
39-
strictEqual(result.stdout, '');
39+
match(result.stdout, /Hello, TypeScript!/);
4040
strictEqual(result.code, 0);
4141
});
4242

@@ -283,9 +283,8 @@ test('execute a TypeScript file with CommonJS syntax requiring .mts', async () =
283283
fixtures.path('typescript/ts/test-require-mts.ts'),
284284
]);
285285

286-
strictEqual(result.stdout, '');
287-
match(result.stderr, /Error \[ERR_REQUIRE_ESM\]: require\(\) of ES Module/);
288-
strictEqual(result.code, 1);
286+
match(result.stdout, /Hello, TypeScript!/);
287+
strictEqual(result.code, 0);
289288
});
290289

291290
test('execute a TypeScript file with CommonJS syntax requiring .mts with require-module', async () => {

test/parallel/test-require-mjs.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// Flags: --no-experimental-require-module
2+
// Previously, this tested that require(esm) throws ERR_REQUIRE_ESM, which is no longer applicable
3+
// since require(esm) is now supported. The test has been repurposed to ensure that the old behavior
4+
// is preserved when the --no-experimental-require-module flag is used.
5+
16
'use strict';
27
require('../common');
38
const assert = require('assert');

0 commit comments

Comments
 (0)