Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm: replace --entry-type with --input-type #27184

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
32 changes: 20 additions & 12 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this left in on purpose?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see the section head:

These errors have never been released, but had been present on master between
releases.

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

Expand Down
80 changes: 49 additions & 31 deletions doc/api/esm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

### <code>--entry-type=module</code> flag

Files ending with `.js` or `.mjs`, or lacking any extension,
will be loaded as ES modules when the `--entry-type=module` flag is set.

```sh
node --experimental-modules --entry-type=module my-app.js
```
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:

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.
- Files ending in `.cjs`.

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`.
- 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 --eval \
"import { sep } from 'path'; console.log(sep);"

echo "import { sep } from 'path'; console.log(sep);" | \
node --experimental-modules --entry-type=module
```
- Strings passed in as an argument to `--eval` or `--print`, or piped to
`node` via `STDIN`, with the flag `--input-type=commonjs`.

### <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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -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'
.
Expand Down Expand Up @@ -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
Expand Down
20 changes: 2 additions & 18 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/check_syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/eval_stdin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
6 changes: 3 additions & 3 deletions lib/internal/main/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
32 changes: 11 additions & 21 deletions lib/internal/modules/esm/default_resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 = {
Expand Down Expand Up @@ -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),
Expand Down
12 changes: 6 additions & 6 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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\"");
}
}

Expand Down Expand Up @@ -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'",
Expand Down
Loading