-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
doc: clarify module system selection #41383
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
Changes from 6 commits
1b1159a
dd7140f
97515fd
c19d161
ce3edd0
be6f791
e9c0b15
4c697b7
2cea6a8
21b45bf
93d6a23
fe05b72
5de6698
b08ec87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| # Command-line options | ||
| # Command-line API | ||
|
|
||
| <!--introduced_in=v5.9.1--> | ||
|
|
||
|
|
@@ -11,16 +11,42 @@ To view this documentation as a manual page in a terminal, run `man node`. | |
|
|
||
| ## Synopsis | ||
|
|
||
| `node [options] [V8 options] [script.js | -e "script" | -] [--] [arguments]` | ||
| `node [options] [V8 options] [<program-entry-point> | -e "script" | -] [--] [arguments]` | ||
|
|
||
| `node inspect [script.js | -e "script" | <host>:<port>] …` | ||
| `node inspect [<program-entry-point> | -e "script" | <host>:<port>] …` | ||
|
|
||
| `node --v8-options` | ||
|
|
||
| Execute without arguments to start the [REPL][]. | ||
|
|
||
| For more info about `node inspect`, see the [debugger][] documentation. | ||
|
|
||
| ## Program entry point | ||
|
|
||
| The program entry point is a specifier-like string. If the string is not an | ||
| absolute path, it's resolved as a relative path from the current working | ||
| directory. That path is then resolved by [CommonJS][] module loader. If no | ||
| corresponding file is found, an error is thrown. | ||
|
|
||
| If a file is found, its path will be passed to the [ECMAScript module loader][] | ||
| under any of the following conditions: | ||
|
|
||
| * The file has an `.mjs` extension. | ||
| * The file nearest parent `package.json` file | ||
| contains a top-level [`"type"`][] field with a value of `"module"`. | ||
| * If the program was started with a command-line flag that forces the entry | ||
| point to be loaded with ECMAScript module loader. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should explicitly refer to Formalizing this behaviour on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To save readers some time, this is the comment where we established that it is, indeed, a bug: #33226 (comment)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR is trying to describe the current behavior of Node.js, not its final or ideal state. I don't call out which CLI flags do trigger this behavior precisely because of that discussion you linked to.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The nature of the fix isn't clear yet so idk if this PR needs to fix it right now. I wouldn't want to block this PR based upon #33226 .
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I only meant that documenting the interaction between Note that this wasn't a blocker by any means, just a suggestion. |
||
|
|
||
| Otherwise, the file is loaded using the CommonJS module loader. See | ||
| [Modules loaders][] for more details. | ||
|
|
||
| ### ECMAScript modules loader entry point caveat | ||
|
|
||
| When loading [ECMAScript module loader][] loads the program entry point, the `node` | ||
| command will only accept as input only files with `.js`, `.mjs`, or `.cjs` | ||
| extensions; and with `.wasm` extensions when | ||
| [`--experimental-wasm-modules`][] is enabled. | ||
|
|
||
| ## Options | ||
|
|
||
| <!-- YAML | ||
|
|
@@ -277,8 +303,8 @@ Enable experimental JSON support for the ES Module loader. | |
| added: v9.0.0 | ||
| --> | ||
|
|
||
| Specify the `module` of a custom experimental [ECMAScript Module loader][]. | ||
| `module` may be either a path to a file, or an ECMAScript Module name. | ||
| Specify the `module` of a custom experimental [ECMAScript module loader][]. | ||
| `module` may be any string accepted as an [`import` specifier][]. | ||
|
|
||
| ### `--experimental-policy` | ||
|
|
||
|
|
@@ -1928,15 +1954,19 @@ $ node --max-old-space-size=1536 index.js | |
| ``` | ||
|
|
||
| [Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/ | ||
| [ECMAScript Module loader]: esm.md#loaders | ||
| [CommonJS]: modules.md | ||
| [ECMAScript module loader]: esm.md#loaders | ||
| [Modules loaders]: packages.md#modules-loaders | ||
| [OSSL_PROVIDER-legacy]: https://www.openssl.org/docs/man3.0/man7/OSSL_PROVIDER-legacy.html | ||
| [REPL]: repl.md | ||
| [ScriptCoverage]: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage | ||
| [Source Map]: https://sourcemaps.info/spec.html | ||
| [Subresource Integrity]: https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity | ||
| [V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html | ||
| [`"type"`]: packages.md#type | ||
| [`--cpu-prof-dir`]: #--cpu-prof-dir | ||
| [`--diagnostic-dir`]: #--diagnostic-dirdirectory | ||
| [`--experimental-wasm-modules`]: #--experimental-wasm-modules | ||
| [`--heap-prof-dir`]: #--heap-prof-dir | ||
| [`--openssl-config`]: #--openssl-configfile | ||
| [`--redirect-warnings`]: #--redirect-warningsfile | ||
|
|
@@ -1949,6 +1979,7 @@ $ node --max-old-space-size=1536 index.js | |
| [`dns.lookup()`]: dns.md#dnslookuphostname-options-callback | ||
| [`dns.setDefaultResultOrder()`]: dns.md#dnssetdefaultresultorderorder | ||
| [`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options | ||
| [`import` specifier]: esm.md#import-specifiers | ||
| [`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn | ||
| [`tls.DEFAULT_MAX_VERSION`]: tls.md#tlsdefault_max_version | ||
| [`tls.DEFAULT_MIN_VERSION`]: tls.md#tlsdefault_min_version | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -94,12 +94,12 @@ provides interoperability between them and its original module format, | |||||
|
|
||||||
| <!-- type=misc --> | ||||||
|
|
||||||
| Node.js treats JavaScript code as CommonJS modules by default. | ||||||
| Authors can tell Node.js to treat JavaScript code as ECMAScript modules | ||||||
| Node.js has two module systems: [CommonJS][] modules and ECMAScript modules. | ||||||
|
|
||||||
| Authors can tell Node.js to use the ECMAScript modules loader | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I just don’t think the docs should have any references to “the CommonJS modules loader” or the “ECMAScript modules loader”—no average user knows what those are. There’s just Node, and how it interprets source code.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK but using the ES module loader has more effect than on simply JS code (it no longer accepts
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add those other implications here, then. Most people reading these docs wouldn't know about those nuances just because the loader is mentioned.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tried to address that in ce3edd0, PTAL. |
||||||
| via the `.mjs` file extension, the `package.json` [`"type"`][] field, or the | ||||||
|
aduh95 marked this conversation as resolved.
|
||||||
| `--input-type` flag. See | ||||||
| [Modules: Packages](packages.md#determining-module-system) for more | ||||||
| details. | ||||||
| [`--input-type`][] flag. Outside of those cases, Node.js will use the CommonJS | ||||||
| module loader. See [Determining module system][] for more details. | ||||||
|
aduh95 marked this conversation as resolved.
|
||||||
|
|
||||||
| <!-- Anchors to make sure old links find a target --> | ||||||
|
|
||||||
|
|
@@ -1425,6 +1425,7 @@ success! | |||||
| [CommonJS]: modules.md | ||||||
| [Conditional exports]: packages.md#conditional-exports | ||||||
| [Core modules]: modules.md#core-modules | ||||||
| [Determining module system]: packages.md#determining-module-system | ||||||
| [Dynamic `import()`]: https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports | ||||||
| [ECMAScript Top-Level `await` proposal]: https://github.com/tc39/proposal-top-level-await/ | ||||||
| [ES Module Integration Proposal for WebAssembly]: https://github.com/webassembly/esm-integration | ||||||
|
|
@@ -1437,6 +1438,7 @@ success! | |||||
| [WHATWG JSON modules specification]: https://html.spec.whatwg.org/#creating-a-json-module-script | ||||||
| [`"exports"`]: packages.md#exports | ||||||
| [`"type"`]: packages.md#type | ||||||
| [`--input-type`]: cli.md#--input-typetype | ||||||
| [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ||||||
| [`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer | ||||||
| [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -51,12 +51,13 @@ along with a reference for the [`package.json`][] fields defined by Node.js. | |||||||||||||||||||||||||||
| ## Determining module system | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| 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: | ||||||||||||||||||||||||||||
| initial input, or when referenced by `import` statements or `import()` | ||||||||||||||||||||||||||||
| expressions: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Files ending in `.mjs`. | ||||||||||||||||||||||||||||
| * Files with an `.mjs` extension. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Files ending in `.js` when the nearest parent `package.json` file contains a | ||||||||||||||||||||||||||||
| top-level [`"type"`][] field with a value of `"module"`. | ||||||||||||||||||||||||||||
| * Files with a `.js` extension when the nearest parent `package.json` file | ||||||||||||||||||||||||||||
| contains a top-level [`"type"`][] field with a value of `"module"`. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Strings passed in as an argument to `--eval`, or piped to `node` via `STDIN`, | ||||||||||||||||||||||||||||
| with the flag `--input-type=module`. | ||||||||||||||||||||||||||||
|
|
@@ -67,12 +68,13 @@ 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: | ||||||||||||||||||||||||||||
| or when referenced by `import` statements, `import()` expressions, or | ||||||||||||||||||||||||||||
| `require()` expressions: | ||||||||||||||||||||||||||||
|
GeoffreyBooth marked this conversation as resolved.
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Files ending in `.cjs`. | ||||||||||||||||||||||||||||
| * Files with a `.cjs` extension. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Files ending in `.js` when the nearest parent `package.json` file contains a | ||||||||||||||||||||||||||||
| top-level field [`"type"`][] with a value of `"commonjs"`. | ||||||||||||||||||||||||||||
| * Files with a `.js` extension when the nearest parent `package.json` file | ||||||||||||||||||||||||||||
| contains a top-level field [`"type"`][] with a value of `"commonjs"`. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * Strings passed in as an argument to `--eval` or `--print`, or piped to `node` | ||||||||||||||||||||||||||||
| via `STDIN`, with the flag `--input-type=commonjs`. | ||||||||||||||||||||||||||||
|
|
@@ -83,6 +85,41 @@ future-proof the package in case the default type of Node.js ever changes, and | |||||||||||||||||||||||||||
| it will also make things easier for build tools and loaders to determine how the | ||||||||||||||||||||||||||||
| files in the package should be interpreted. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ### Modules loaders | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Node.js has two system for resolving a specifier and load modules. | ||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| There is the CommonJS module loader: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * It is fully synchronous. | ||||||||||||||||||||||||||||
| * It is monkey patchable. | ||||||||||||||||||||||||||||
| * When resolving a specifier, if no exact match is found, it will try to add | ||||||||||||||||||||||||||||
| extensions (`.js`, `.json`, and finally `.node`). | ||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that's true, if the specifier points to an existing directory, then an exact match is found – we have a Folders as modules section that explains it. Otherwise, we would have to specify it first tries to load the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then maybe mention the folder resolution without spelling it out?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Lines 97 to 99 in 93d6a23
EDIT: no you're right, we should document the order here. Lines 97 to 100 in fe05b72
|
||||||||||||||||||||||||||||
| * It supports [folders as modules][]. | ||||||||||||||||||||||||||||
| * It treats `.json` as JSON text files. | ||||||||||||||||||||||||||||
|
GeoffreyBooth marked this conversation as resolved.
|
||||||||||||||||||||||||||||
| * `.node` files are interpreted as compiled addon modules loaded with | ||||||||||||||||||||||||||||
| `process.dlopen()`. | ||||||||||||||||||||||||||||
| * It treats files that do not have `.json` or `.node` extension as JavaScript | ||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||
| text files. | ||||||||||||||||||||||||||||
| * It cannot be used to load ECMAScript modules. Attempting to do so will result | ||||||||||||||||||||||||||||
| in a [`ERR_REQUIRE_ESM`][] error. | ||||||||||||||||||||||||||||
| * It can be accessed using `require` function. | ||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if you noticed, but I tried to list the same features in both lists, so user can compare the difference between CJS and ESM loaders. If we add an item here, can we add it to the ESM list as well?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could combine the two * It allows one CommonJS module to load another using the `require` function.
`require` cannot be used to load ECMAScript modules. Attempting to do so
will result in a [`ERR_REQUIRE_ESM`][] error.
* It allows CommonJS modules to asynchronously import ECMAScript modules,
using `import()` expressions.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It also allows ES module to load a CJS module using
I don't see how this is related to the CJS loader.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went with Lines 103 to 107 in 21b45bf
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I don't "like" with this last version is it gives the impression that if an ESM file do not use any ESM specific syntax, CJS loader would (try to) parse it as CJS. Can we have a version without using Do we really need to document here that
ESM loader can load more than just ESM, so it may not be obvious that CJS only loads CJS?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Can it though? Doesn’t it just call the CommonJS loader to handle cases of We can leave out the error message, sure. But then I don’t think there’s anything left of this bullet point, and so we should just remove it. Both loaders use the other to handle the other system’s modules. The only thing worth mentioning is how
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO there's a clear difference: with I'm going to land as is, hopefully we can improve this part of the docs in future PRs.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But can it really? If you CommonJS modules load more than just CommonJS, and the inverse for ES modules, and that’s what matters to end users. Stating that the loader can only handle CommonJS just adds confusion. I think that matters to users is that All this other stuff about what the loaders can do is unnecessary detail that can confuse people. I understand the desire to keep the whole list focused on the CommonJS loader, which is why I’m thinking it’s best to just leave out this detail unless you want to make this bullet about |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| There is the ECMAScript module loader: | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| * It is Asynchronous. | ||||||||||||||||||||||||||||
| * It is not monkey patchable, can be customized using [loader hooks][]. | ||||||||||||||||||||||||||||
| * No extension searching, the specifier must point to the exact URL of the file. | ||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||
| * It does not support folders as modules. | ||||||||||||||||||||||||||||
| * Import assertion are needed to load JSON modules (behind | ||||||||||||||||||||||||||||
| `--experimental-json-modules` flag). | ||||||||||||||||||||||||||||
| * It only accepts `.js`, `.mjs`, and `.cjs` extensions for JavaScript text | ||||||||||||||||||||||||||||
| files. | ||||||||||||||||||||||||||||
| * It can be used to load (JavaScript) CommonJS modules. It passes the module | ||||||||||||||||||||||||||||
| content through the `es-module-lexer` to assess what are its exports, convert | ||||||||||||||||||||||||||||
| its URL to an absolute path and load it using the CommonJS module loader. | ||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||
| * It can be accessed using `import`. | ||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
aduh95 marked this conversation as resolved.
|
||||||||||||||||||||||||||||
| ### `package.json` and file extensions | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Within a package, the [`package.json`][] [`"type"`][] field defines how | ||||||||||||||||||||||||||||
|
|
@@ -1233,9 +1270,12 @@ This field defines [subpath imports][] for the current package. | |||||||||||||||||||||||||||
| [`--conditions` / `-C` flag]: #resolving-user-conditions | ||||||||||||||||||||||||||||
| [`--no-addons` flag]: cli.md#--no-addons | ||||||||||||||||||||||||||||
| [`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.md#err_package_path_not_exported | ||||||||||||||||||||||||||||
| [`ERR_REQUIRE_ESM`]: errors.md#err_require_esm | ||||||||||||||||||||||||||||
| [`esm`]: https://github.com/standard-things/esm#readme | ||||||||||||||||||||||||||||
| [`package.json`]: #nodejs-packagejson-field-definitions | ||||||||||||||||||||||||||||
| [entry points]: #package-entry-points | ||||||||||||||||||||||||||||
| [folders as modules]: modules.md#folders-as-modules | ||||||||||||||||||||||||||||
| [loader hooks]: esm.md#loaders | ||||||||||||||||||||||||||||
| [self-reference]: #self-referencing-a-package-using-its-name | ||||||||||||||||||||||||||||
| [subpath exports]: #subpath-exports | ||||||||||||||||||||||||||||
| [subpath imports]: #subpath-imports | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| { | ||
| "doc/api/synopsis.md": { | ||
| "command line options": "cli.html#command-line-options", | ||
| "command line options": "cli.html#options", | ||
| "web server": "http.html" | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.