Skip to content

Commit 66dcb2a

Browse files
GeoffreyBoothRafaelGSS
authored andcommitted
module: unflag detect-module
PR-URL: #53619 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 3e25be7 commit 66dcb2a

20 files changed

+120
-130
lines changed

doc/api/cli.md

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -923,39 +923,6 @@ files with no extension will be treated as WebAssembly if they begin with the
923923
WebAssembly magic number (`\0asm`); otherwise they will be treated as ES module
924924
JavaScript.
925925

926-
### `--experimental-detect-module`
927-
928-
<!-- YAML
929-
added:
930-
- v21.1.0
931-
- v20.10.0
932-
-->
933-
934-
> Stability: 1.1 - Active development
935-
936-
Node.js will inspect the source code of ambiguous input to determine whether it
937-
contains ES module syntax; if such syntax is detected, the input will be treated
938-
as an ES module.
939-
940-
Ambiguous input is defined as:
941-
942-
* Files with a `.js` extension or no extension; and either no controlling
943-
`package.json` file or one that lacks a `type` field; and
944-
`--experimental-default-type` is not specified.
945-
* String input (`--eval` or STDIN) when neither `--input-type` nor
946-
`--experimental-default-type` are specified.
947-
948-
ES module syntax is defined as syntax that would throw when evaluated as
949-
CommonJS. This includes the following:
950-
951-
* `import` statements (but _not_ `import()` expressions, which are valid in
952-
CommonJS).
953-
* `export` statements.
954-
* `import.meta` references.
955-
* `await` at the top level of a module.
956-
* Lexical redeclarations of the CommonJS wrapper variables (`require`, `module`,
957-
`exports`, `__dirname`, `__filename`).
958-
959926
### `--experimental-eventsource`
960927

961928
<!-- YAML
@@ -1610,6 +1577,21 @@ added: v18.0.0
16101577

16111578
Disable exposition of [Fetch API][] on the global scope.
16121579

1580+
### `--no-experimental-detect-module`
1581+
1582+
<!-- YAML
1583+
added:
1584+
- v21.1.0
1585+
- v20.10.0
1586+
changes:
1587+
- version:
1588+
- REPLACEME
1589+
pr-url: https://github.com/nodejs/node/pull/53619
1590+
description: Syntax detection is enabled by default.
1591+
-->
1592+
1593+
Disable using [syntax detection][] to determine module type.
1594+
16131595
### `--no-experimental-global-customevent`
16141596

16151597
<!-- YAML
@@ -3569,6 +3551,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
35693551
[semi-space]: https://www.memorymanagement.org/glossary/s.html#semi.space
35703552
[single executable application]: single-executable-applications.md
35713553
[snapshot testing]: test.md#snapshot-testing
3554+
[syntax detection]: packages.md#syntax-detection
35723555
[test reporters]: test.md#test-reporters
35733556
[timezone IDs]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
35743557
[tracking issue for user-land snapshots]: https://github.com/nodejs/node/issues/44014

doc/api/esm.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,8 +1016,7 @@ _isImports_, _conditions_)
10161016
> 10. If _url_ ends in _".js"_, then
10171017
> 1. If _packageType_ is not **null**, then
10181018
> 1. Return _packageType_.
1019-
> 2. If `--experimental-detect-module` is enabled and the result of
1020-
> **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
1019+
> 2. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
10211020
> 1. Return _"module"_.
10221021
> 3. Return _"commonjs"_.
10231022
> 11. If _url_ does not have any extension, then
@@ -1027,8 +1026,7 @@ _isImports_, _conditions_)
10271026
> 1. Return _"wasm"_.
10281027
> 2. If _packageType_ is not **null**, then
10291028
> 1. Return _packageType_.
1030-
> 3. If `--experimental-detect-module` is enabled and the source of
1031-
> module contains static import or export syntax, then
1029+
> 3. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
10321030
> 1. Return _"module"_.
10331031
> 4. Return _"commonjs"_.
10341032
> 12. Return **undefined** (will throw during load phase).

doc/api/modules.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ loaded by `require()` meets the following requirements:
185185
1. The file has a `.mjs` extension.
186186
2. The file has a `.js` extension, and the closest `package.json` contains `"type": "module"`
187187
3. The file has a `.js` extension, the closest `package.json` does not contain
188-
`"type": "commonjs"`, and `--experimental-detect-module` is enabled.
188+
`"type": "commonjs"`, and the module contains ES module syntax.
189189

190190
`require()` will load the requested module as an ES Module, and return
191191
the module namespace object. In this case it is similar to dynamic
@@ -272,7 +272,7 @@ require(X) from module at path Y
272272
273273
MAYBE_DETECT_AND_LOAD(X)
274274
1. If X parses as a CommonJS module, load X as a CommonJS module. STOP.
275-
2. Else, if `--experimental-require-module` and `--experimental-detect-module` are
275+
2. Else, if `--experimental-require-module` is
276276
enabled, and the source code of X can be parsed as ECMAScript module using
277277
<a href="esm.md#resolver-algorithm-specification">DETECT_MODULE_SYNTAX defined in
278278
the ESM resolver</a>,

doc/api/packages.md

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ expressions:
6969
* Strings passed in as an argument to `--eval`, or piped to `node` via `STDIN`,
7070
with the flag `--input-type=module`.
7171

72-
* When using [`--experimental-detect-module`][], code containing syntax only
73-
successfully parsed as [ES modules][], such as `import` or `export`
74-
statements or `import.meta`, having no explicit marker of how it should be
75-
interpreted. Explicit markers are `.mjs` or `.cjs` extensions, `package.json`
76-
`"type"` fields with either `"module"` or `"commonjs"` values, or
77-
`--input-type` or `--experimental-default-type` flags. Dynamic `import()`
78-
expressions are supported in either CommonJS or ES modules and would not
79-
cause a file to be treated as an ES module.
72+
* Code containing syntax only successfully parsed as [ES modules][], such as
73+
`import` or `export` statements or `import.meta`, with no explicit marker of
74+
how it should be interpreted. Explicit markers are `.mjs` or `.cjs`
75+
extensions, `package.json` `"type"` fields with either `"module"` or
76+
`"commonjs"` values, or `--input-type` or `--experimental-default-type` flags.
77+
Dynamic `import()` expressions are supported in either CommonJS or ES modules
78+
and would not force a file to be treated as an ES module. See
79+
[Syntax detection][].
8080

8181
Node.js will treat the following as [CommonJS][] when passed to `node` as the
8282
initial input, or when referenced by `import` statements or `import()`
@@ -115,6 +115,44 @@ package in case the default type of Node.js ever changes, and it will also make
115115
things easier for build tools and loaders to determine how the files in the
116116
package should be interpreted.
117117

118+
### Syntax detection
119+
120+
<!-- YAML
121+
added:
122+
- v21.1.0
123+
- v20.10.0
124+
changes:
125+
- version:
126+
- REPLACEME
127+
pr-url: https://github.com/nodejs/node/pull/53619
128+
description: Syntax detection is enabled by default.
129+
-->
130+
131+
> Stability: 1.2 - Release candidate
132+
133+
Node.js will inspect the source code of ambiguous input to determine whether it
134+
contains ES module syntax; if such syntax is detected, the input will be treated
135+
as an ES module.
136+
137+
Ambiguous input is defined as:
138+
139+
* Files with a `.js` extension or no extension; and either no controlling
140+
`package.json` file or one that lacks a `type` field; and
141+
`--experimental-default-type` is not specified.
142+
* String input (`--eval` or STDIN) when neither `--input-type` nor
143+
`--experimental-default-type` are specified.
144+
145+
ES module syntax is defined as syntax that would throw when evaluated as
146+
CommonJS. This includes the following:
147+
148+
* `import` statements (but _not_ `import()` expressions, which are valid in
149+
CommonJS).
150+
* `export` statements.
151+
* `import.meta` references.
152+
* `await` at the top level of a module.
153+
* Lexical redeclarations of the CommonJS wrapper variables (`require`, `module`,
154+
`exports`, `__dirname`, `__filename`).
155+
118156
### Modules loaders
119157

120158
Node.js has two systems for resolving a specifier and loading modules.
@@ -1355,6 +1393,7 @@ This field defines [subpath imports][] for the current package.
13551393
[ES modules]: esm.md
13561394
[Node.js documentation for this section]: https://github.com/nodejs/node/blob/HEAD/doc/api/packages.md#conditions-definitions
13571395
[Runtime Keys]: https://runtime-keys.proposal.wintercg.org/
1396+
[Syntax detection]: #syntax-detection
13581397
[WinterCG]: https://wintercg.org/
13591398
[`"exports"`]: #exports
13601399
[`"imports"`]: #imports
@@ -1364,7 +1403,6 @@ This field defines [subpath imports][] for the current package.
13641403
[`"type"`]: #type
13651404
[`--conditions` / `-C` flag]: #resolving-user-conditions
13661405
[`--experimental-default-type`]: cli.md#--experimental-default-typetype
1367-
[`--experimental-detect-module`]: cli.md#--experimental-detect-module
13681406
[`--no-addons` flag]: cli.md#--no-addons
13691407
[`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.md#err_package_path_not_exported
13701408
[`esm`]: https://github.com/standard-things/esm#readme

lib/internal/main/check_syntax.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,23 @@ function loadESMIfNeeded(cb) {
5757
}
5858

5959
async function checkSyntax(source, filename) {
60-
let isModule = true;
60+
let format;
6161
if (filename === '[stdin]' || filename === '[eval]') {
62-
isModule = getOptionValue('--input-type') === 'module' ||
63-
(getOptionValue('--experimental-default-type') === 'module' && getOptionValue('--input-type') !== 'commonjs');
62+
format = (getOptionValue('--input-type') === 'module' ||
63+
(getOptionValue('--experimental-default-type') === 'module' && getOptionValue('--input-type') !== 'commonjs')) ?
64+
'module' : 'commonjs';
6465
} else {
6566
const { defaultResolve } = require('internal/modules/esm/resolve');
6667
const { defaultGetFormat } = require('internal/modules/esm/get_format');
6768
const { url } = await defaultResolve(pathToFileURL(filename).toString());
68-
const format = await defaultGetFormat(new URL(url));
69-
isModule = format === 'module';
69+
format = await defaultGetFormat(new URL(url));
7070
}
7171

72-
if (isModule) {
72+
if (format === 'module') {
7373
const { ModuleWrap } = internalBinding('module_wrap');
7474
new ModuleWrap(filename, undefined, source, 0, 0);
7575
return;
7676
}
7777

78-
wrapSafe(filename, source, undefined, 'commonjs');
78+
wrapSafe(filename, source, undefined, format);
7979
}

lib/internal/modules/run_main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ function runEntryPointWithESMLoader(callback) {
150150
* by `require('module')`) even when the entry point is ESM.
151151
* This monkey-patchable code is bypassed under `--experimental-default-type=module`.
152152
* Because of backwards compatibility, this function is exposed publicly via `import { runMain } from 'node:module'`.
153-
* When `--experimental-detect-module` is passed, this function will attempt to run ambiguous (no explicit extension, no
153+
* Because of module detection, this function will attempt to run ambiguous (no explicit extension, no
154154
* `package.json` type field) entry points as CommonJS first; under certain conditions, it will retry running as ESM.
155155
* @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js`
156156
*/

src/node_options.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
356356
"when ambiguous modules fail to evaluate because they contain "
357357
"ES module syntax, try again to evaluate them as ES modules",
358358
&EnvironmentOptions::detect_module,
359-
kAllowedInEnvvar);
359+
kAllowedInEnvvar,
360+
true);
360361
AddOption("--experimental-print-required-tla",
361362
"Print pending top-level await. If --experimental-require-module "
362363
"is true, evaluate asynchronous graphs loaded by `require()` but "

src/node_options.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class EnvironmentOptions : public Options {
115115
public:
116116
bool abort_on_uncaught_exception = false;
117117
std::vector<std::string> conditions;
118-
bool detect_module = false;
118+
bool detect_module = true;
119119
bool print_required_tla = false;
120120
bool require_module = false;
121121
std::string dns_result_order;

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ describe('ESM: importing CJS', { concurrency: !process.env.TEST_PARALLEL }, () =
2121
const invalidEntry = fixtures.path('/es-modules/cjs-exports-invalid.mjs');
2222
const { code, signal, stderr } = await spawnPromisified(execPath, [invalidEntry]);
2323

24+
assert.match(stderr, /SyntaxError: The requested module '\.\/invalid-cjs\.js' does not provide an export named 'default'/);
2425
assert.strictEqual(code, 1);
2526
assert.strictEqual(signal, null);
26-
assert.ok(stderr.includes('Warning: To load an ES module'));
27-
assert.ok(stderr.includes('Unexpected token \'export\''));
2827
});
2928
});

0 commit comments

Comments
 (0)