Skip to content

Commit 5d4be39

Browse files
committed
doc: correct module loading descriptions
The existing description is outdated, and exposes too many details that are subject to change. - There is no point conceptualizing "two module loaders", in reality the boundary is blurred since the two invoke each other to support require(esm) and import(cjs). The distinction lies not in what kind of module is being requested/which loader is used, but only in how the the module request is initiated (via `require()` or `import()`). The inner working of the loaders are subject to change and not suitable to be documented. - It should not mention monkey patching in the documentation, as publicly supported universal hooks are already provided through `module.registerHooks()`, and so there's no need to single out any of them in terms of loader hooks support either. - Remove the description about whether they are asynchronous or synchronous, which is also implementation detail subject to change. - Add missing descriptions about how .ts, .mts and .cts are treated, and `.node` is also supported in import now. - There is no need to specially mention .node treatment in cli.md, link to the explanations about loading from `import` in packages.md instead.
1 parent 5dd478c commit 5d4be39

File tree

2 files changed

+60
-60
lines changed

2 files changed

+60
-60
lines changed

doc/api/cli.md

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,22 @@ For more info about `node inspect`, see the [debugger][] documentation.
2525

2626
The program entry point is a specifier-like string. If the string is not an
2727
absolute path, it's resolved as a relative path from the current working
28-
directory. That path is then resolved by [CommonJS][] module loader. If no
29-
corresponding file is found, an error is thrown.
28+
directory. That entry point string is then resolved as if it's been requested
29+
by `require()` from the current working directory. If no corresponding file
30+
is found, an error is thrown.
3031

31-
If a file is found, its path will be passed to the
32-
[ES module loader][Modules loaders] under any of the following conditions:
32+
The resolved path is usually also loaded as if it's been requested by `require()`,
33+
unless one of the conditions below apply, then it's loaded as if it's been requested
34+
by `import()`:
3335

3436
* The program was started with a command-line flag that forces the entry
3537
point to be loaded with ECMAScript module loader, such as `--import`.
36-
* The file has an `.mjs` or `.wasm` extension.
38+
* The file has an `.mjs`, `.mts` or `.wasm` extension.
3739
* The file does not have a `.cjs` extension, and the nearest parent
3840
`package.json` file contains a top-level [`"type"`][] field with a value of
3941
`"module"`.
4042

41-
Otherwise, the file is loaded using the CommonJS module loader. See
42-
[Modules loaders][] for more details.
43-
44-
### ECMAScript modules loader entry point caveat
45-
46-
When loading, the [ES module loader][Modules loaders] loads the program
47-
entry point, the `node` command will accept as input only files with `.js`,
48-
`.mjs`, or `.cjs` extensions. With the following flags, additional file
49-
extensions are enabled:
50-
51-
* [`--experimental-addon-modules`][] for files with `.node` extension.
43+
See [module resolution and loading][] for more details.
5244

5345
## Options
5446

@@ -4073,7 +4065,6 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
40734065
[#42511]: https://github.com/nodejs/node/issues/42511
40744066
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/
40754067
[Chromium's policy for locally trusted certificates]: https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/faq.md#does-the-chrome-certificate-verifier-consider-local-trust-decisions
4076-
[CommonJS]: modules.md
40774068
[CommonJS module]: modules.md
40784069
[DEP0025 warning]: deprecations.md#dep0025-requirenodesys
40794070
[ECMAScript module]: esm.md#modules-ecmascript-modules
@@ -4083,7 +4074,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
40834074
[Loading ECMAScript modules using `require()`]: modules.md#loading-ecmascript-modules-using-require
40844075
[Module customization hooks]: module.md#customization-hooks
40854076
[Module customization hooks: enabling]: module.md#enabling
4086-
[Modules loaders]: packages.md#modules-loaders
4077+
[Module resolution and loading]: packages.md#module-resolution-and-loading
40874078
[Navigator API]: globals.md#navigator
40884079
[Node.js issue tracker]: https://github.com/nodejs/node/issues
40894080
[OSSL_PROVIDER-legacy]: https://www.openssl.org/docs/man3.0/man7/OSSL_PROVIDER-legacy.html
@@ -4109,7 +4100,6 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
41094100
[`--disable-sigusr1`]: #--disable-sigusr1
41104101
[`--env-file-if-exists`]: #--env-file-if-existsfile
41114102
[`--env-file`]: #--env-filefile
4112-
[`--experimental-addon-modules`]: #--experimental-addon-modules
41134103
[`--experimental-sea-config`]: single-executable-applications.md#generating-single-executable-preparation-blobs
41144104
[`--heap-prof-dir`]: #--heap-prof-dir
41154105
[`--import`]: #--importmodule

doc/api/packages.md

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -142,46 +142,52 @@ CommonJS. This includes the following:
142142
* Lexical redeclarations of the CommonJS wrapper variables (`require`, `module`,
143143
`exports`, `__dirname`, `__filename`).
144144

145-
### Modules loaders
146-
147-
Node.js has two systems for resolving a specifier and loading modules.
148-
149-
There is the CommonJS module loader:
150-
151-
* It is fully synchronous.
152-
* It is responsible for handling `require()` calls.
153-
* It is monkey patchable.
154-
* It supports [folders as modules][].
155-
* When resolving a specifier, if no exact match is found, it will try to add
156-
extensions (`.js`, `.json`, and finally `.node`) and then attempt to resolve
157-
[folders as modules][].
158-
* It treats `.json` as JSON text files.
159-
* `.node` files are interpreted as compiled addon modules loaded with
160-
`process.dlopen()`.
161-
* It treats all files that lack `.json` or `.node` extensions as JavaScript
162-
text files.
163-
* It can only be used to [load ECMAScript modules from CommonJS modules][] if
164-
the module graph is synchronous (that contains no top-level `await`).
165-
When used to load a JavaScript text file that is not an ECMAScript module,
166-
the file will be loaded as a CommonJS module.
167-
168-
There is the ECMAScript module loader:
169-
170-
* It is asynchronous, unless it's being used to load modules for `require()`.
171-
* It is responsible for handling `import` statements and `import()` expressions.
172-
* It is not monkey patchable, can be customized using [loader hooks][].
173-
* It does not support folders as modules, directory indexes (e.g.
174-
`'./startup/index.js'`) must be fully specified.
175-
* It does no extension searching. A file extension must be provided
176-
when the specifier is a relative or absolute file URL.
177-
* It can load JSON modules, but an import type attribute is required.
178-
* It accepts only `.js`, `.mjs`, and `.cjs` extensions for JavaScript text
179-
files.
180-
* It can be used to load JavaScript CommonJS modules. Such modules
181-
are passed through the `cjs-module-lexer` to try to identify named exports,
182-
which are available if they can be determined through static analysis.
183-
Imported CommonJS modules have their URLs converted to absolute
184-
paths and are then loaded via the CommonJS module loader.
145+
### Module resolution and loading
146+
147+
Node.js has two types of module resolution and loading, chosen based on how the module is requested.
148+
149+
When a module is requested via `require()`:
150+
151+
* Resolution:
152+
* The resolution initiated by `require()` supports [folders as modules][].
153+
* When resolving a specifier, if no exact match is found, `require()` will try to add
154+
extensions (`.js`, `.json`, and finally `.node`) and then attempt to resolve
155+
[folders as modules][].
156+
* Loading:
157+
* `.json` files are treated as JSON text files.
158+
* `.node` files are interpreted as compiled addon modules loaded with `process.dlopen()`.
159+
* `.ts`, `.mts` and `.cts` files are treated as [TypeScript][] text files.
160+
* Files with any other extension, or without extensions, are treated as JavaScript
161+
text files.
162+
* `require()` only be used to [load ECMAScript modules from CommonJS modules][] if
163+
the [ECMAScript module][ES Module] and its dependencies are synchronous
164+
(i.e. they do not contain top-level `await`).
165+
166+
When a module is requested via `import` statements or `import()` expressions:
167+
168+
* Resolution:
169+
* The resolution of `import`/`import()` does not support folders as modules,
170+
directory indexes (e.g. `'./startup/index.js'`) must be fully specified.
171+
* It does not perform extension searching. A file extension must be provided
172+
when the specifier is a relative or absolute file URL.
173+
* Loading:
174+
* `.json` files are treated as JSON text files. When importing JSON modules,
175+
an import type attribute is required (e.g.
176+
`import json from './data.json' with { type: 'json' }`).
177+
* `.node` files are interpreted as compiled addon modules loaded with
178+
`process.dlopen()`, if [`--experimental-addon-modules`][] is enabled.
179+
* `.ts`, `.mts` and `.cts` files are treated as [TypeScript][] text files.
180+
* It accepts only `.js`, `.mjs`, and `.cjs` extensions for JavaScript text
181+
files.
182+
* `.wasm` files are treated as [WebAssembly modules][].
183+
* Any other file extensions will result in a
184+
[`ERR_UNKNOWN_FILE_EXTENSION`][] error.
185+
* `import`/`import()` can be used to load JavaScript [CommonJS modules][commonjs].
186+
Such modules are passed through the `cjs-module-lexer` to try to identify named
187+
exports, which are available if they can be determined through static analysis.
188+
189+
Regardless of how a module is requested, the resolution and loading process can be customized
190+
using [loader hooks][].
185191

186192
### `package.json` and file extensions
187193

@@ -1151,21 +1157,25 @@ This field defines [subpath imports][] for the current package.
11511157
[Node.js documentation for this section]: https://github.com/nodejs/node/blob/HEAD/doc/api/packages.md#conditions-definitions
11521158
[Runtime Keys]: https://runtime-keys.proposal.wintercg.org/
11531159
[Syntax detection]: #syntax-detection
1160+
[TypeScript]: typescript.md
1161+
[WebAssembly modules]: esm.md#wasm-modules
11541162
[WinterCG]: https://wintercg.org/
11551163
[`"exports"`]: #exports
11561164
[`"imports"`]: #imports
11571165
[`"main"`]: #main
11581166
[`"name"`]: #name
11591167
[`"type"`]: #type
11601168
[`--conditions` / `-C` flag]: #resolving-user-conditions
1169+
[`--experimental-addon-modules`]: cli.md#--experimental-addon-modules
11611170
[`--no-addons` flag]: cli.md#--no-addons
11621171
[`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.md#err_package_path_not_exported
1172+
[`ERR_UNKNOWN_FILE_EXTENSION`]: errors.md#err_unknown_file_extension
11631173
[`package.json`]: #nodejs-packagejson-field-definitions
11641174
[entry points]: #package-entry-points
11651175
[folders as modules]: modules.md#folders-as-modules
11661176
[import maps]: https://github.com/WICG/import-maps
11671177
[load ECMAScript modules from CommonJS modules]: modules.md#loading-ecmascript-modules-using-require
1168-
[loader hooks]: esm.md#loaders
1178+
[loader hooks]: module.md#customization-hooks
11691179
[packages folder mapping]: https://github.com/WICG/import-maps#packages-via-trailing-slashes
11701180
[self-reference]: #self-referencing-a-package-using-its-name
11711181
[subpath exports]: #subpath-exports

0 commit comments

Comments
 (0)