Skip to content

Commit 1cf4efe

Browse files
GeoffreyBoothjoyeecheung
authored andcommitted
module: unflag detect-module
PR-URL: nodejs#53619 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 119661e commit 1cf4efe

20 files changed

+122
-131
lines changed

doc/api/cli.md

+16-32
Original file line numberDiff line numberDiff line change
@@ -887,38 +887,6 @@ files with no extension will be treated as WebAssembly if they begin with the
887887
WebAssembly magic number (`\0asm`); otherwise they will be treated as ES module
888888
JavaScript.
889889

890-
### `--experimental-detect-module`
891-
892-
<!-- YAML
893-
added:
894-
- v20.10.0
895-
-->
896-
897-
> Stability: 1.1 - Active development
898-
899-
Node.js will inspect the source code of ambiguous input to determine whether it
900-
contains ES module syntax; if such syntax is detected, the input will be treated
901-
as an ES module.
902-
903-
Ambiguous input is defined as:
904-
905-
* Files with a `.js` extension or no extension; and either no controlling
906-
`package.json` file or one that lacks a `type` field; and
907-
`--experimental-default-type` is not specified.
908-
* String input (`--eval` or STDIN) when neither `--input-type` nor
909-
`--experimental-default-type` are specified.
910-
911-
ES module syntax is defined as syntax that would throw when evaluated as
912-
CommonJS. This includes the following:
913-
914-
* `import` statements (but _not_ `import()` expressions, which are valid in
915-
CommonJS).
916-
* `export` statements.
917-
* `import.meta` references.
918-
* `await` at the top level of a module.
919-
* Lexical redeclarations of the CommonJS wrapper variables (`require`, `module`,
920-
`exports`, `__dirname`, `__filename`).
921-
922890
### `--experimental-eventsource`
923891

924892
<!-- YAML
@@ -1540,6 +1508,21 @@ added: v0.8.0
15401508

15411509
Silence deprecation warnings.
15421510

1511+
### `--no-experimental-detect-module`
1512+
1513+
<!-- YAML
1514+
added:
1515+
- v21.1.0
1516+
- v20.10.0
1517+
changes:
1518+
- version:
1519+
- REPLACEME
1520+
pr-url: https://github.com/nodejs/node/pull/53619
1521+
description: Syntax detection is enabled by default.
1522+
-->
1523+
1524+
Disable using [syntax detection][] to determine module type.
1525+
15431526
### `--no-experimental-fetch`
15441527

15451528
<!-- YAML
@@ -3384,6 +3367,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
33843367
[security warning]: #warning-binding-inspector-to-a-public-ipport-combination-is-insecure
33853368
[semi-space]: https://www.memorymanagement.org/glossary/s.html#semi.space
33863369
[single executable application]: single-executable-applications.md
3370+
[syntax detection]: packages.md#syntax-detection
33873371
[test reporters]: test.md#test-reporters
33883372
[timezone IDs]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
33893373
[tracking issue for user-land snapshots]: https://github.com/nodejs/node/issues/44014

doc/api/esm.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -1071,8 +1071,7 @@ _isImports_, _conditions_)
10711071
> 10. If _url_ ends in _".js"_, then
10721072
> 1. If _packageType_ is not **null**, then
10731073
> 1. Return _packageType_.
1074-
> 2. If `--experimental-detect-module` is enabled and the result of
1075-
> **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
1074+
> 2. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
10761075
> 1. Return _"module"_.
10771076
> 3. Return _"commonjs"_.
10781077
> 11. If _url_ does not have any extension, then
@@ -1082,8 +1081,7 @@ _isImports_, _conditions_)
10821081
> 1. Return _"wasm"_.
10831082
> 2. If _packageType_ is not **null**, then
10841083
> 1. Return _packageType_.
1085-
> 3. If `--experimental-detect-module` is enabled and the source of
1086-
> module contains static import or export syntax, then
1084+
> 3. If the result of **DETECT\_MODULE\_SYNTAX**(_source_) is true, then
10871085
> 1. Return _"module"_.
10881086
> 4. Return _"commonjs"_.
10891087
> 12. Return **undefined** (will throw during load phase).

doc/api/modules.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ loaded by `require()` meets the following requirements:
192192
1. The file has a `.mjs` extension.
193193
2. The file has a `.js` extension, and the closest `package.json` contains `"type": "module"`
194194
3. The file has a `.js` extension, the closest `package.json` does not contain
195-
`"type": "commonjs"`, and `--experimental-detect-module` is enabled.
195+
`"type": "commonjs"`, and the module contains ES module syntax.
196196

197197
`require()` will load the requested module as an ES Module, and return
198198
the module namespace object. In this case it is similar to dynamic
@@ -279,7 +279,7 @@ require(X) from module at path Y
279279
280280
MAYBE_DETECT_AND_LOAD(X)
281281
1. If X parses as a CommonJS module, load X as a CommonJS module. STOP.
282-
2. Else, if `--experimental-require-module` and `--experimental-detect-module` are
282+
2. Else, if `--experimental-require-module` is
283283
enabled, and the source code of X can be parsed as ECMAScript module using
284284
<a href="esm.md#resolver-algorithm-specification">DETECT_MODULE_SYNTAX defined in
285285
the ESM resolver</a>,

doc/api/packages.md

+47-9
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.
@@ -1369,6 +1407,7 @@ This field defines [subpath imports][] for the current package.
13691407
[ES modules]: esm.md
13701408
[Node.js documentation for this section]: https://github.com/nodejs/node/blob/HEAD/doc/api/packages.md#conditions-definitions
13711409
[Runtime Keys]: https://runtime-keys.proposal.wintercg.org/
1410+
[Syntax detection]: #syntax-detection
13721411
[WinterCG]: https://wintercg.org/
13731412
[`"exports"`]: #exports
13741413
[`"imports"`]: #imports
@@ -1378,7 +1417,6 @@ This field defines [subpath imports][] for the current package.
13781417
[`"type"`]: #type
13791418
[`--conditions` / `-C` flag]: #resolving-user-conditions
13801419
[`--experimental-default-type`]: cli.md#--experimental-default-typetype
1381-
[`--experimental-detect-module`]: cli.md#--experimental-detect-module
13821420
[`--no-addons` flag]: cli.md#--no-addons
13831421
[`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.md#err_package_path_not_exported
13841422
[`esm`]: https://github.com/standard-things/esm#readme

lib/internal/main/check_syntax.js

+7-7
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

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

src/node_options.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
364364
"when ambiguous modules fail to evaluate because they contain "
365365
"ES module syntax, try again to evaluate them as ES modules",
366366
&EnvironmentOptions::detect_module,
367-
kAllowedInEnvvar);
367+
kAllowedInEnvvar,
368+
true);
368369
AddOption("--experimental-print-required-tla",
369370
"Print pending top-level await. If --experimental-require-module "
370371
"is true, evaluate asynchronous graphs loaded by `require()` but "

src/node_options.h

+1-1
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

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ describe('ESM: importing CJS', { concurrency: true }, () => {
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)