esm: replace --entry-type with --input-type
New flag is for string input only PR-URL: https://github.com/nodejs/node/pull/27184 Reviewed-By: Jan Krems <jan.krems@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Myles Borins <myles.borins@gmail.com>
This commit is contained in:
parent
f85ef977e6
commit
96e46d37c4
@ -134,19 +134,6 @@ added: v6.0.0
|
||||
Enable FIPS-compliant crypto at startup. (Requires Node.js to be built with
|
||||
`./configure --openssl-fips`.)
|
||||
|
||||
### `--entry-type=type`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
Used with `--experimental-modules`, this configures Node.js to interpret the
|
||||
initial entry point as CommonJS or as an ES module.
|
||||
|
||||
Valid values are `"commonjs"` and `"module"`. The default is to infer from
|
||||
the file extension and the `"type"` field in the nearest parent `package.json`.
|
||||
|
||||
Works for executing a file as well as `--eval`, `--print`, `STDIN`.
|
||||
|
||||
### `--es-module-specifier-resolution=mode`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
@ -261,6 +248,17 @@ added: v0.11.15
|
||||
|
||||
Specify ICU data load path. (Overrides `NODE_ICU_DATA`.)
|
||||
|
||||
### `--input-type=type`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
Used with `--experimental-modules`, this configures Node.js to interpret string
|
||||
input as CommonJS or as an ES module. String input is input via `--eval`,
|
||||
`--print`, or `STDIN`.
|
||||
|
||||
Valid values are `"commonjs"` and `"module"`. The default is `"commonjs"`.
|
||||
|
||||
### `--inspect-brk[=[host:]port]`
|
||||
<!-- YAML
|
||||
added: v7.6.0
|
||||
|
@ -854,18 +854,6 @@ provided.
|
||||
Encoding provided to `TextDecoder()` API was not one of the
|
||||
[WHATWG Supported Encodings][].
|
||||
|
||||
<a id="ERR_ENTRY_TYPE_MISMATCH"></a>
|
||||
#### ERR_ENTRY_TYPE_MISMATCH
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
The `--entry-type=commonjs` flag was used to attempt to execute an `.mjs` file
|
||||
or a `.js` file where the nearest parent `package.json` contains
|
||||
`"type": "module"`; or
|
||||
the `--entry-type=module` flag was used to attempt to execute a `.cjs` file or
|
||||
a `.js` file where the nearest parent `package.json` either lacks a `"type"`
|
||||
field or contains `"type": "commonjs"`.
|
||||
|
||||
<a id="ERR_FALSY_VALUE_REJECTION"></a>
|
||||
### ERR_FALSY_VALUE_REJECTION
|
||||
|
||||
@ -1166,6 +1154,14 @@ is set for the `Http2Stream`.
|
||||
An option pair is incompatible with each other and can not be used at the same
|
||||
time.
|
||||
|
||||
<a id="ERR_INPUT_TYPE_NOT_ALLOWED"></a>
|
||||
### ERR_INPUT_TYPE_NOT_ALLOWED
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
The `--input-type` flag was used to attempt to execute a file. This flag can
|
||||
only be used with input via `--eval`, `--print` or `STDIN`.
|
||||
|
||||
<a id="ERR_INSPECTOR_ALREADY_CONNECTED"></a>
|
||||
### ERR_INSPECTOR_ALREADY_CONNECTED
|
||||
|
||||
@ -2223,6 +2219,18 @@ closed.
|
||||
These errors have never been released, but had been present on master between
|
||||
releases.
|
||||
|
||||
<a id="ERR_ENTRY_TYPE_MISMATCH"></a>
|
||||
#### ERR_ENTRY_TYPE_MISMATCH
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
The `--entry-type=commonjs` flag was used to attempt to execute an `.mjs` file
|
||||
or a `.js` file where the nearest parent `package.json` contains
|
||||
`"type": "module"`; or
|
||||
the `--entry-type=module` flag was used to attempt to execute a `.cjs` file or
|
||||
a `.js` file where the nearest parent `package.json` either lacks a `"type"`
|
||||
field or contains `"type": "commonjs"`.
|
||||
|
||||
<a id="ERR_FS_WATCHER_ALREADY_STARTED"></a>
|
||||
#### ERR_FS_WATCHER_ALREADY_STARTED
|
||||
|
||||
|
@ -30,45 +30,37 @@ specifier resolution, and default behavior.
|
||||
The `--experimental-modules` flag can be used to enable support for
|
||||
ECMAScript modules (ES modules).
|
||||
|
||||
## Running Node.js with an ECMAScript Module
|
||||
Once enabled, Node.js will treat the following as ES modules when passed to
|
||||
`node` as the initial input, or when referenced by `import` statements within
|
||||
ES module code:
|
||||
|
||||
There are a few ways to start Node.js with an ES module as its input.
|
||||
- Files ending in `.mjs`.
|
||||
|
||||
### Initial entry point with an <code>.mjs</code> extension
|
||||
- Files ending in `.js`, or extensionless files, when the nearest parent
|
||||
`package.json` file contains a top-level field `"type"` with a value of
|
||||
`"module"`.
|
||||
|
||||
A file ending with `.mjs` passed to Node.js as an initial entry point will be
|
||||
loaded as an ES module.
|
||||
- Strings passed in as an argument to `--eval` or `--print`, or piped to
|
||||
`node` via `STDIN`, with the flag `--input-type=module`.
|
||||
|
||||
```sh
|
||||
node --experimental-modules my-app.mjs
|
||||
```
|
||||
Node.js will treat as CommonJS all other forms of input, such as `.js` files
|
||||
where the nearest parent `package.json` file contains no top-level `"type"`
|
||||
field, or string input without the flag `--input-type`. This behavior is to
|
||||
preserve backward compatibility. However, now that Node.js supports both
|
||||
CommonJS and ES modules, it is best to be explicit whenever possible. Node.js
|
||||
will treat the following as CommonJS when passed to `node` as the initial input,
|
||||
or when referenced by `import` statements within ES module code:
|
||||
|
||||
### <code>--entry-type=module</code> flag
|
||||
- Files ending in `.cjs`.
|
||||
|
||||
Files ending with `.js` or `.mjs`, or lacking any extension,
|
||||
will be loaded as ES modules when the `--entry-type=module` flag is set.
|
||||
- Files ending in `.js`, or extensionless files, when the nearest parent
|
||||
`package.json` file contains a top-level field `"type"` with a value of
|
||||
`"commonjs"`.
|
||||
|
||||
```sh
|
||||
node --experimental-modules --entry-type=module my-app.js
|
||||
```
|
||||
- Strings passed in as an argument to `--eval` or `--print`, or piped to
|
||||
`node` via `STDIN`, with the flag `--input-type=commonjs`.
|
||||
|
||||
For completeness there is also `--entry-type=commonjs`, for explicitly running
|
||||
a `.js` file as CommonJS. This is the default behavior if `--entry-type` is
|
||||
unspecified.
|
||||
|
||||
The `--entry-type=module` flag can also be used to configure Node.js to treat
|
||||
as an ES module input sent in via `--eval` or `--print` (or `-e` or `-p`) or
|
||||
piped to Node.js via `STDIN`.
|
||||
|
||||
```sh
|
||||
node --experimental-modules --entry-type=module --eval \
|
||||
"import { sep } from 'path'; console.log(sep);"
|
||||
|
||||
echo "import { sep } from 'path'; console.log(sep);" | \
|
||||
node --experimental-modules --entry-type=module
|
||||
```
|
||||
|
||||
### <code>package.json</code> <code>"type"</code> field
|
||||
## <code>package.json</code> <code>"type"</code> field
|
||||
|
||||
Files ending with `.js` or `.mjs`, or lacking any extension,
|
||||
will be loaded as ES modules when the nearest parent `package.json` file
|
||||
@ -97,6 +89,14 @@ If the volume root is reached and no `package.json` is found,
|
||||
Node.js defers to the default, a `package.json` with no `"type"`
|
||||
field.
|
||||
|
||||
`import` statements of `.js` and extensionless files are treated as ES modules
|
||||
if the nearest parent `package.json` contains `"type": "module"`.
|
||||
|
||||
```js
|
||||
// my-app.js, part of the same example as above
|
||||
import './startup.js'; // Loaded as ES module because of package.json
|
||||
```
|
||||
|
||||
## Package Scope and File Extensions
|
||||
|
||||
A folder containing a `package.json` file, and all subfolders below that
|
||||
@ -156,6 +156,24 @@ package scope:
|
||||
extension (since both `.js` and `.cjs` files are treated as CommonJS within a
|
||||
`"commonjs"` package scope).
|
||||
|
||||
## <code>--input-type</code> flag
|
||||
|
||||
Strings passed in as an argument to `--eval` or `--print` (or `-e` or `-p`), or
|
||||
piped to `node` via `STDIN`, will be treated as ES modules when the
|
||||
`--input-type=module` flag is set.
|
||||
|
||||
```sh
|
||||
node --experimental-modules --input-type=module --eval \
|
||||
"import { sep } from 'path'; console.log(sep);"
|
||||
|
||||
echo "import { sep } from 'path'; console.log(sep);" | \
|
||||
node --experimental-modules --input-type=module
|
||||
```
|
||||
|
||||
For completeness there is also `--input-type=commonjs`, for explicitly running
|
||||
string input as CommonJS. This is the default behavior if `--input-type` is
|
||||
unspecified.
|
||||
|
||||
## Package Entry Points
|
||||
|
||||
The `package.json` `"main"` field defines the entry point for a package,
|
||||
|
@ -119,9 +119,6 @@ Enable FIPS-compliant crypto at startup.
|
||||
Requires Node.js to be built with
|
||||
.Sy ./configure --openssl-fips .
|
||||
.
|
||||
.It Fl -entry-type Ns = Ns Ar type
|
||||
Set the top-level module resolution type.
|
||||
.
|
||||
.It Fl -es-module-specifier-resolution
|
||||
Select extension resolution algorithm for ES Modules; either 'explicit' (default) or 'node'
|
||||
.
|
||||
@ -170,6 +167,9 @@ Specify ICU data load path.
|
||||
Overrides
|
||||
.Ev NODE_ICU_DATA .
|
||||
.
|
||||
.It Fl -input-type Ns = Ns Ar type
|
||||
Set the module resolution type for input via --eval, --print or STDIN.
|
||||
.
|
||||
.It Fl -inspect-brk Ns = Ns Ar [host:]port
|
||||
Activate inspector on
|
||||
.Ar host:port
|
||||
|
@ -679,24 +679,6 @@ E('ERR_ENCODING_INVALID_ENCODED_DATA', function(encoding, ret) {
|
||||
}, TypeError);
|
||||
E('ERR_ENCODING_NOT_SUPPORTED', 'The "%s" encoding is not supported',
|
||||
RangeError);
|
||||
E('ERR_ENTRY_TYPE_MISMATCH', (filename, ext, typeFlag, conflict) => {
|
||||
const typeString =
|
||||
typeFlag === 'module' ? '--entry-type=module' : '--entry-type=commonjs';
|
||||
// --entry-type mismatches file extension
|
||||
if (conflict === 'extension') {
|
||||
return `Extension ${ext} is not supported for ` +
|
||||
`${typeString} loading ${filename}`;
|
||||
}
|
||||
assert(
|
||||
conflict === 'scope',
|
||||
'"conflict" value unknown. Set this argument to "extension" or "scope"'
|
||||
);
|
||||
// --entry-type mismatches package.json "type"
|
||||
return `Cannot use ${typeString} because nearest parent package.json ` +
|
||||
((typeFlag === 'module') ?
|
||||
'includes "type": "commonjs"' : 'includes "type": "module",') +
|
||||
` which controls the type to use for ${filename}`;
|
||||
}, TypeError);
|
||||
E('ERR_FALSY_VALUE_REJECTION', function(reason) {
|
||||
this.reason = reason;
|
||||
return 'Promise was rejected with falsy value';
|
||||
@ -809,6 +791,8 @@ E('ERR_HTTP_TRAILER_INVALID',
|
||||
'Trailers are invalid with this transfer encoding', Error);
|
||||
E('ERR_INCOMPATIBLE_OPTION_PAIR',
|
||||
'Option "%s" can not be used in combination with option "%s"', TypeError);
|
||||
E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' +
|
||||
'input via --eval, --print, or STDIN', Error);
|
||||
E('ERR_INSPECTOR_ALREADY_CONNECTED', '%s is already connected', Error);
|
||||
E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error);
|
||||
E('ERR_INSPECTOR_COMMAND', 'Inspector error %d: %s', Error);
|
||||
|
@ -60,7 +60,7 @@ function checkSyntax(source, filename) {
|
||||
if (experimentalModules) {
|
||||
let isModule = false;
|
||||
if (filename === '[stdin]' || filename === '[eval]') {
|
||||
isModule = getOptionValue('--entry-type') === 'module';
|
||||
isModule = getOptionValue('--input-type') === 'module';
|
||||
} else {
|
||||
const resolve = require('internal/modules/esm/default_resolve');
|
||||
const { format } = resolve(pathToFileURL(filename).toString());
|
||||
|
@ -17,7 +17,7 @@ markBootstrapComplete();
|
||||
|
||||
readStdin((code) => {
|
||||
process._eval = code;
|
||||
if (require('internal/options').getOptionValue('--entry-type') === 'module')
|
||||
if (require('internal/options').getOptionValue('--input-type') === 'module')
|
||||
evalModule(process._eval);
|
||||
else
|
||||
evalScript('[stdin]', process._eval, process._breakFirstLine);
|
||||
|
@ -14,7 +14,7 @@ const source = getOptionValue('--eval');
|
||||
prepareMainThreadExecution();
|
||||
addBuiltinLibsToObject(global);
|
||||
markBootstrapComplete();
|
||||
if (getOptionValue('--entry-type') === 'module')
|
||||
if (getOptionValue('--input-type') === 'module')
|
||||
evalModule(source);
|
||||
else
|
||||
evalScript('[eval]', source, process._breakFirstLine);
|
||||
|
@ -15,11 +15,11 @@ const console = require('internal/console/global');
|
||||
|
||||
prepareMainThreadExecution();
|
||||
|
||||
// --entry-type flag not supported in REPL
|
||||
if (require('internal/options').getOptionValue('--entry-type')) {
|
||||
// --input-type flag not supported in REPL
|
||||
if (require('internal/options').getOptionValue('--input-type')) {
|
||||
// If we can't write to stderr, we'd like to make this a noop,
|
||||
// so use console.error.
|
||||
console.error('Cannot specify --entry-type for REPL');
|
||||
console.error('Cannot specify --input-type for REPL');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -9,12 +9,12 @@ const { getOptionValue } = require('internal/options');
|
||||
const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
||||
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
||||
const experimentalJsonModules = getOptionValue('--experimental-json-modules');
|
||||
const typeFlag = getOptionValue('--entry-type');
|
||||
const typeFlag = getOptionValue('--input-type');
|
||||
|
||||
const { resolve: moduleWrapResolve,
|
||||
getPackageType } = internalBinding('module_wrap');
|
||||
const { pathToFileURL, fileURLToPath } = require('internal/url');
|
||||
const { ERR_ENTRY_TYPE_MISMATCH,
|
||||
const { ERR_INPUT_TYPE_NOT_ALLOWED,
|
||||
ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;
|
||||
|
||||
const {
|
||||
@ -25,7 +25,7 @@ const {
|
||||
const realpathCache = new SafeMap();
|
||||
|
||||
// const TYPE_NONE = 0;
|
||||
const TYPE_COMMONJS = 1;
|
||||
// const TYPE_COMMONJS = 1;
|
||||
const TYPE_MODULE = 2;
|
||||
|
||||
const extensionFormatMap = {
|
||||
@ -86,26 +86,16 @@ function resolve(specifier, parentURL) {
|
||||
let format = extMap[ext];
|
||||
|
||||
if (isMain && typeFlag) {
|
||||
// Conflict between explicit extension (.mjs, .cjs) and --entry-type
|
||||
if (ext === '.cjs' && typeFlag === 'module' ||
|
||||
ext === '.mjs' && typeFlag === 'commonjs') {
|
||||
throw new ERR_ENTRY_TYPE_MISMATCH(
|
||||
fileURLToPath(url), ext, typeFlag, 'extension');
|
||||
}
|
||||
|
||||
// Conflict between package scope type and --entry-type
|
||||
if (ext === '.js') {
|
||||
if (type === TYPE_MODULE && typeFlag === 'commonjs' ||
|
||||
type === TYPE_COMMONJS && typeFlag === 'module') {
|
||||
throw new ERR_ENTRY_TYPE_MISMATCH(
|
||||
fileURLToPath(url), ext, typeFlag, 'scope');
|
||||
}
|
||||
}
|
||||
// This is the initial entry point to the program, and --input-type has
|
||||
// been passed as an option; but --input-type can only be used with
|
||||
// --eval, --print or STDIN string input. It is not allowed with file
|
||||
// input, to avoid user confusion over how expansive the effect of the
|
||||
// flag should be (i.e. entry point only, package scope surrounding the
|
||||
// entry point, etc.).
|
||||
throw new ERR_INPUT_TYPE_NOT_ALLOWED();
|
||||
}
|
||||
if (!format) {
|
||||
if (isMain && typeFlag)
|
||||
format = typeFlag;
|
||||
else if (isMain)
|
||||
if (isMain)
|
||||
format = type === TYPE_MODULE ? 'module' : 'commonjs';
|
||||
else
|
||||
throw new ERR_UNKNOWN_FILE_EXTENSION(fileURLToPath(url),
|
||||
|
@ -109,11 +109,11 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
|
||||
|
||||
if (!module_type.empty()) {
|
||||
if (!experimental_modules) {
|
||||
errors->push_back("--entry-type requires "
|
||||
errors->push_back("--input-type requires "
|
||||
"--experimental-modules to be enabled");
|
||||
}
|
||||
if (module_type != "commonjs" && module_type != "module") {
|
||||
errors->push_back("--entry-type must be \"module\" or \"commonjs\"");
|
||||
errors->push_back("--input-type must be \"module\" or \"commonjs\"");
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,15 +289,15 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
|
||||
"(default: llhttp).",
|
||||
&EnvironmentOptions::http_parser,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--input-type",
|
||||
"set module type for string input",
|
||||
&EnvironmentOptions::module_type,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--loader",
|
||||
"(with --experimental-modules) use the specified file as a "
|
||||
"custom loader",
|
||||
&EnvironmentOptions::userland_loader,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--entry-type",
|
||||
"set module type name of the entry point",
|
||||
&EnvironmentOptions::module_type,
|
||||
kAllowedInEnvironment);
|
||||
AddOption("--es-module-specifier-resolution",
|
||||
"Select extension resolution algorithm for es modules; "
|
||||
"either 'explicit' (default) or 'node'",
|
||||
|
@ -5,14 +5,13 @@ const fixtures = require('../common/fixtures');
|
||||
const { spawn } = require('child_process');
|
||||
const assert = require('assert');
|
||||
|
||||
const entry = fixtures.path('/es-modules/noext-esm');
|
||||
const entry = fixtures.path('/es-modules/package-type-module/noext-esm');
|
||||
|
||||
// Run a module that does not have extension
|
||||
// This is to ensure the --entry-type works as expected
|
||||
// Run a module that does not have extension.
|
||||
// This is to ensure that "type": "module" applies to extensionless files.
|
||||
|
||||
const child = spawn(process.execPath, [
|
||||
'--experimental-modules',
|
||||
'--entry-type=module',
|
||||
entry
|
||||
]);
|
||||
|
||||
|
@ -19,17 +19,9 @@ expect('', packageTypeModuleMain, 'package-type-module');
|
||||
expect('', packageTypeCommonJsMain, 'package-type-commonjs');
|
||||
expect('', packageWithoutTypeMain, 'package-without-type');
|
||||
|
||||
// Check that running with --entry-type and no package.json "type" works
|
||||
expect('--entry-type=commonjs', packageWithoutTypeMain, 'package-without-type');
|
||||
expect('--entry-type=module', packageWithoutTypeMain, 'package-without-type');
|
||||
|
||||
// Check that running with conflicting --entry-type flags throws errors
|
||||
expect('--entry-type=commonjs', mjsFile, 'ERR_ENTRY_TYPE_MISMATCH', true);
|
||||
expect('--entry-type=module', cjsFile, 'ERR_ENTRY_TYPE_MISMATCH', true);
|
||||
expect('--entry-type=commonjs', packageTypeModuleMain,
|
||||
'ERR_ENTRY_TYPE_MISMATCH', true);
|
||||
expect('--entry-type=module', packageTypeCommonJsMain,
|
||||
'ERR_ENTRY_TYPE_MISMATCH', true);
|
||||
// Check that --input-type isn't allowed for files
|
||||
expect('--input-type=module', packageTypeModuleMain,
|
||||
'ERR_INPUT_TYPE_NOT_ALLOWED', true);
|
||||
|
||||
function expect(opt = '', inputFile, want, wantsError = false) {
|
||||
// TODO: Remove when --experimental-modules is unflagged
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Flags: --experimental-modules --entry-type=module
|
||||
// Flags: --experimental-modules
|
||||
/* eslint-disable node-core/required-modules */
|
||||
import cjs from '../fixtures/baz.js';
|
||||
import '../common/index.mjs';
|
||||
|
@ -34,12 +34,12 @@ syntaxArgs.forEach(function(arg) {
|
||||
assert.strictEqual(c.status, 1);
|
||||
});
|
||||
|
||||
// Check --entry-type=module
|
||||
// Check --input-type=module
|
||||
syntaxArgs.forEach(function(arg) {
|
||||
const stdin = 'export var p = 5; var foo bar;';
|
||||
const c = spawnSync(
|
||||
node,
|
||||
['--experimental-modules', '--entry-type=module', '--no-warnings', arg],
|
||||
['--experimental-modules', '--input-type=module', '--no-warnings', arg],
|
||||
{ encoding: 'utf8', input: stdin }
|
||||
);
|
||||
|
||||
|
@ -25,12 +25,12 @@ syntaxArgs.forEach(function(arg) {
|
||||
assert.strictEqual(c.status, 0);
|
||||
});
|
||||
|
||||
// Check --entry-type=module
|
||||
// Check --input-type=module
|
||||
syntaxArgs.forEach(function(arg) {
|
||||
const stdin = 'export var p = 5; throw new Error("should not get run");';
|
||||
const c = spawnSync(
|
||||
node,
|
||||
['--experimental-modules', '--no-warnings', '--entry-type=module', arg],
|
||||
['--experimental-modules', '--no-warnings', '--input-type=module', arg],
|
||||
{ encoding: 'utf8', input: stdin }
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user