Skip to content

Commit 0a4cfef

Browse files
committed
esm: make specifier flag clearly experimental
`--es-module-specifier-resolution` is the only flagged portion of the ESM implementation that does not have the word experimental in the flag name. This commit changes the flag to: `--experimental-specifier-resolution` `--es-module-specifier-resolution` remains as an alias for backwards compatibility but it is no longer documented. PR-URL: #30678 Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Guy Bedford <[email protected]>
1 parent d7972b7 commit 0a4cfef

11 files changed

+95
-31
lines changed

doc/api/cli.md

+15-15
Original file line numberDiff line numberDiff line change
@@ -156,20 +156,6 @@ Enable experimental Source Map V3 support for stack traces.
156156
Currently, overriding `Error.prepareStackTrace` is ignored when the
157157
`--enable-source-maps` flag is set.
158158

159-
### `--es-module-specifier-resolution=mode`
160-
<!-- YAML
161-
added: v12.0.0
162-
-->
163-
164-
To be used in conjunction with `--experimental-modules`. Sets the resolution
165-
algorithm for resolving specifiers. Valid options are `explicit` and `node`.
166-
167-
The default is `explicit`, which requires providing the full path to a
168-
module. The `node` mode will enable support for optional file extensions and
169-
the ability to import a directory that has an index file.
170-
171-
Please see [customizing ESM specifier resolution][] for example usage.
172-
173159
### `--experimental-conditional-exports`
174160
<!-- YAML
175161
added: REPLACEME
@@ -222,6 +208,20 @@ added: REPLACEME
222208
Enable experimental support for a package using `require` or `import` to load
223209
itself.
224210

211+
### `--experimental-specifier-resolution=mode`
212+
<!-- YAML
213+
added: REPLACEME
214+
-->
215+
216+
Sets the resolution algorithm for resolving ES module specifiers. Valid options
217+
are `explicit` and `node`.
218+
219+
The default is `explicit`, which requires providing the full path to a
220+
module. The `node` mode will enable support for optional file extensions and
221+
the ability to import a directory that has an index file.
222+
223+
Please see [customizing ESM specifier resolution][] for example usage.
224+
225225
### `--experimental-vm-modules`
226226
<!-- YAML
227227
added: v9.6.0
@@ -1072,7 +1072,6 @@ Node.js options that are allowed are:
10721072
<!-- node-options-node start -->
10731073
* `--enable-fips`
10741074
* `--enable-source-maps`
1075-
* `--es-module-specifier-resolution`
10761075
* `--experimental-conditional-exports`
10771076
* `--experimental-json-modules`
10781077
* `--experimental-loader`
@@ -1081,6 +1080,7 @@ Node.js options that are allowed are:
10811080
* `--experimental-repl-await`
10821081
* `--experimental-report`
10831082
* `--experimental-resolve-self`
1083+
* `--experimental-specifier-resolution`
10841084
* `--experimental-vm-modules`
10851085
* `--experimental-wasm-modules`
10861086
* `--force-context-aware`

doc/api/esm.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,7 @@ the CommonJS loader. One of the behavior differences is automatic resolution
13751375
of file extensions and the ability to import directories that have an index
13761376
file.
13771377
1378-
The `--es-module-specifier-resolution=[mode]` flag can be used to customize
1378+
The `--experimental-specifier-resolution=[mode]` flag can be used to customize
13791379
the extension resolution algorithm. The default mode is `explicit`, which
13801380
requires the full path to a module be provided to the loader. To enable the
13811381
automatic extension resolution and importing from directories that include an
@@ -1386,7 +1386,7 @@ $ node --experimental-modules index.mjs
13861386
success!
13871387
$ node --experimental-modules index #Failure!
13881388
Error: Cannot find module
1389-
$ node --experimental-modules --es-module-specifier-resolution=node index
1389+
$ node --experimental-modules --experimental-specifier-resolution=node index
13901390
success!
13911391
```
13921392

doc/node.1

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,6 @@ Enable FIPS-compliant crypto at startup.
110110
Requires Node.js to be built with
111111
.Sy ./configure --openssl-fips .
112112
.
113-
.It Fl -es-module-specifier-resolution
114-
Select extension resolution algorithm for ES Modules; either 'explicit' (default) or 'node'
115-
.
116113
.It Fl -experimental-conditional-exports
117114
Enable experimental support for "require" and "node" conditional export targets.
118115
.
@@ -130,6 +127,9 @@ Enable experimental top-level
130127
.Sy await
131128
keyword support in REPL.
132129
.
130+
.It Fl -experimental-specifier-resolution
131+
Select extension resolution algorithm for ES Modules; either 'explicit' (default) or 'node'
132+
.
133133
.It Fl -experimental-report
134134
Enable experimental
135135
.Sy diagnostic report

lib/internal/modules/esm/default_resolve.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const { getOptionValue } = require('internal/options');
99
const preserveSymlinks = getOptionValue('--preserve-symlinks');
1010
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
1111
const experimentalJsonModules = getOptionValue('--experimental-json-modules');
12-
const esModuleSpecifierResolution =
13-
getOptionValue('--es-module-specifier-resolution');
12+
const experimentalSpeciferResolution =
13+
getOptionValue('--experimental-specifier-resolution');
1414
const typeFlag = getOptionValue('--input-type');
1515
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
1616
const { resolve: moduleWrapResolve,
@@ -108,10 +108,14 @@ function resolve(specifier, parentURL) {
108108
if (ext === '.js' || (!format && isMain))
109109
format = getPackageType(url.href) === TYPE_MODULE ? 'module' : 'commonjs';
110110
if (!format) {
111-
if (esModuleSpecifierResolution === 'node')
111+
if (experimentalSpeciferResolution === 'node') {
112+
process.emitWarning(
113+
'The Node.js specifier resolution in ESM is experimental.',
114+
'ExperimentalWarning');
112115
format = legacyExtensionFormatMap[ext];
113-
else
116+
} else {
114117
throw new ERR_UNKNOWN_FILE_EXTENSION(fileURLToPath(url));
118+
}
115119
}
116120
return { url: `${url}`, format };
117121
}

src/module_wrap.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ inline Maybe<URL> ResolveIndex(const URL& search) {
789789
Maybe<URL> FinalizeResolution(Environment* env,
790790
const URL& resolved,
791791
const URL& base) {
792-
if (env->options()->es_module_specifier_resolution == "node") {
792+
if (env->options()->experimental_specifier_resolution == "node") {
793793
Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
794794
if (!file.IsNothing()) {
795795
return file;
@@ -1053,7 +1053,7 @@ Maybe<URL> PackageMainResolve(Environment* env,
10531053
return Just(resolved);
10541054
}
10551055
}
1056-
if (env->options()->es_module_specifier_resolution == "node") {
1056+
if (env->options()->experimental_specifier_resolution == "node") {
10571057
if (pcfg.has_main == HasMain::Yes) {
10581058
return FinalizeResolution(env, URL(pcfg.main, pjson_url), base);
10591059
} else {

src/node_options.cc

+26-4
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,27 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
155155
errors->push_back("--es-module-specifier-resolution requires "
156156
"--experimental-modules be enabled");
157157
}
158-
if (es_module_specifier_resolution != "node" &&
159-
es_module_specifier_resolution != "explicit") {
160-
errors->push_back("invalid value for --es-module-specifier-resolution");
158+
if (!experimental_specifier_resolution.empty()) {
159+
errors->push_back(
160+
"bad option: cannot use --es-module-specifier-resolution"
161+
" and --experimental-specifier-resolution at the same time");
162+
} else {
163+
experimental_specifier_resolution = es_module_specifier_resolution;
164+
if (experimental_specifier_resolution != "node" &&
165+
experimental_specifier_resolution != "explicit") {
166+
errors->push_back(
167+
"invalid value for --es-module-specifier-resolution");
168+
}
169+
}
170+
} else if (!experimental_specifier_resolution.empty()) {
171+
if (!experimental_modules) {
172+
errors->push_back("--experimental-specifier-resolution requires "
173+
"--experimental-modules be enabled");
174+
}
175+
if (experimental_specifier_resolution != "node" &&
176+
experimental_specifier_resolution != "explicit") {
177+
errors->push_back(
178+
"invalid value for --experimental-specifier-resolution");
161179
}
162180
}
163181

@@ -404,9 +422,13 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
404422
"set module type for string input",
405423
&EnvironmentOptions::module_type,
406424
kAllowedInEnvironment);
407-
AddOption("--es-module-specifier-resolution",
425+
AddOption("--experimental-specifier-resolution",
408426
"Select extension resolution algorithm for es modules; "
409427
"either 'explicit' (default) or 'node'",
428+
&EnvironmentOptions::experimental_specifier_resolution,
429+
kAllowedInEnvironment);
430+
AddOption("--es-module-specifier-resolution",
431+
"",
410432
&EnvironmentOptions::es_module_specifier_resolution,
411433
kAllowedInEnvironment);
412434
AddOption("--no-deprecation",

src/node_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class EnvironmentOptions : public Options {
105105
bool experimental_json_modules = false;
106106
bool experimental_modules = false;
107107
bool experimental_resolve_self = false;
108+
std::string experimental_specifier_resolution;
108109
std::string es_module_specifier_resolution;
109110
bool experimental_wasm_modules = false;
110111
std::string module_type;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Flags: --experimental-modules
2+
import { mustCall } from '../common/index.mjs';
3+
import { exec } from 'child_process';
4+
import assert from 'assert';
5+
6+
const expectedError =
7+
'cannot use --es-module-specifier-resolution ' +
8+
'and --experimental-specifier-resolution at the same time';
9+
10+
const flags = '--experimental-modules ' +
11+
'--es-module-specifier-resolution=node ' +
12+
'--experimental-specifier-resolution=node';
13+
14+
exec(`${process.execPath} ${flags}`, {
15+
timeout: 300
16+
}, mustCall((error) => {
17+
assert(error.message.includes(expectedError));
18+
}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Flags: --experimental-modules --es-module-specifier-resolution=node
2+
import '../common/index.mjs';
3+
import assert from 'assert';
4+
5+
// commonJS index.js
6+
import commonjs from '../fixtures/es-module-specifiers/package-type-commonjs';
7+
// esm index.js
8+
import module from '../fixtures/es-module-specifiers/package-type-module';
9+
// Notice the trailing slash
10+
import success, { explicit, implicit, implicitModule }
11+
from '../fixtures/es-module-specifiers/';
12+
13+
assert.strictEqual(commonjs, 'commonjs');
14+
assert.strictEqual(module, 'module');
15+
assert.strictEqual(success, 'success');
16+
assert.strictEqual(explicit, 'esm');
17+
assert.strictEqual(implicit, 'cjs');
18+
assert.strictEqual(implicitModule, 'cjs');

test/es-module/test-esm-specifiers.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Flags: --experimental-modules --es-module-specifier-resolution=node
1+
// Flags: --experimental-modules --experimental-specifier-resolution=node
22
import { mustNotCall } from '../common/index.mjs';
33
import assert from 'assert';
44

test/parallel/test-process-env-allowed-flags-are-documented.js

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const undocumented = difference(process.allowedNodeEnvironmentFlags,
8585
documented);
8686
// Remove intentionally undocumented options.
8787
assert(undocumented.delete('--debug-arraybuffer-allocations'));
88+
assert(undocumented.delete('--es-module-specifier-resolution'));
8889
assert(undocumented.delete('--experimental-worker'));
8990
assert(undocumented.delete('--no-node-snapshot'));
9091
assert(undocumented.delete('--loader'));

0 commit comments

Comments
 (0)