mirror of
https://github.com/nodejs/node.git
synced 2025-04-28 21:46:48 +00:00

Some checks are pending
Coverage Linux (without intl) / coverage-linux-without-intl (push) Waiting to run
Coverage Linux / coverage-linux (push) Waiting to run
Coverage Windows / coverage-windows (push) Waiting to run
Test and upload documentation to artifacts / build-docs (push) Waiting to run
Linters / lint-addon-docs (push) Waiting to run
Linters / lint-cpp (push) Waiting to run
Linters / format-cpp (push) Waiting to run
Linters / lint-js-and-md (push) Waiting to run
Linters / lint-py (push) Waiting to run
Linters / lint-yaml (push) Waiting to run
Linters / lint-sh (push) Waiting to run
Linters / lint-codeowners (push) Waiting to run
Linters / lint-pr-url (push) Waiting to run
Linters / lint-readme (push) Waiting to run
Notify on Push / Notify on Force Push on `main` (push) Waiting to run
Notify on Push / Notify on Push on `main` that lacks metadata (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Notable changes: assert: * (SEMVER-MINOR) implement partial error comparison (Ruben Bridgewater) https://github.com/nodejs/node/pull/57370 * (SEMVER-MINOR) improve partialDeepStrictEqual (Ruben Bridgewater) https://github.com/nodejs/node/pull/57370 cli: * (SEMVER-MINOR) allow --cpu-prof* in NODE_OPTIONS (Carlos Espa) https://github.com/nodejs/node/pull/57018 crypto: * update root certificates to NSS 3.108 (Node.js GitHub Bot) https://github.com/nodejs/node/pull/57381 * (SEMVER-MINOR) support --use-system-ca on Windows (Joyee Cheung) https://github.com/nodejs/node/pull/56833 * (SEMVER-MINOR) added support for reading certificates from macOS system store (Tim Jacomb) https://github.com/nodejs/node/pull/56599 deps: * update timezone to 2025a (Node.js GitHub Bot) https://github.com/nodejs/node/pull/56876 deps,tools: * (SEMVER-MINOR) add zstd 1.5.6 (Jan Martin) https://github.com/nodejs/node/pull/52100 dns: * (SEMVER-MINOR) add TLSA record query and parsing (Rithvik Vibhu) https://github.com/nodejs/node/pull/52983 doc: * add @geeksilva97 to collaborators (Edy Silva) https://github.com/nodejs/node/pull/57241 module: * (SEMVER-MINOR) use synchronous hooks for preparsing in import(cjs) (Joyee Cheung) https://github.com/nodejs/node/pull/55698 * (SEMVER-MINOR) implement module.registerHooks() (Joyee Cheung) https://github.com/nodejs/node/pull/55698 process: * (SEMVER-MINOR) add execve (Paolo Insogna) https://github.com/nodejs/node/pull/56496 * (SEMVER-MINOR) add threadCpuUsage (Paolo Insogna) https://github.com/nodejs/node/pull/56467 sqlite: * (SEMVER-MINOR) add StatementSync.prototype.columns() (Colin Ihrig) https://github.com/nodejs/node/pull/57490 * (SEMVER-MINOR) allow returning `ArrayBufferView`s from user-defined functions (René) https://github.com/nodejs/node/pull/56790 src: * set signal inspector io thread name (RafaelGSS) https://github.com/nodejs/node/pull/56416 * set thread name for main thread and v8 worker (RafaelGSS) https://github.com/nodejs/node/pull/56416 * set worker thread name using worker.name (RafaelGSS) https://github.com/nodejs/node/pull/56416 * use a default thread name for inspector (RafaelGSS) https://github.com/nodejs/node/pull/56416 tls: * (SEMVER-MINOR) implement tls.getCACertificates() (Joyee Cheung) https://github.com/nodejs/node/pull/57107 util: * (SEMVER-MINOR) expose diff function used by the assertion errors (Giovanni Bucci) https://github.com/nodejs/node/pull/57462 v8: * (SEMVER-MINOR) add v8.getCppHeapStatistics() method (Aditi) https://github.com/nodejs/node/pull/57146 zlib: * (SEMVER-MINOR) add zstd support (Jan Martin) https://github.com/nodejs/node/pull/52100 PR-URL: https://github.com/nodejs/node/pull/57840
1810 lines
63 KiB
Markdown
1810 lines
63 KiB
Markdown
# Modules: `node:module` API
|
|
|
|
<!--introduced_in=v12.20.0-->
|
|
|
|
<!-- YAML
|
|
added: v0.3.7
|
|
-->
|
|
|
|
## The `Module` object
|
|
|
|
* {Object}
|
|
|
|
Provides general utility methods when interacting with instances of
|
|
`Module`, the [`module`][] variable often seen in [CommonJS][] modules. Accessed
|
|
via `import 'node:module'` or `require('node:module')`.
|
|
|
|
### `module.builtinModules`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v9.3.0
|
|
- v8.10.0
|
|
- v6.13.0
|
|
changes:
|
|
- version: v23.5.0
|
|
pr-url: https://github.com/nodejs/node/pull/56185
|
|
description: The list now also contains prefix-only modules.
|
|
-->
|
|
|
|
* {string\[]}
|
|
|
|
A list of the names of all modules provided by Node.js. Can be used to verify
|
|
if a module is maintained by a third party or not.
|
|
|
|
`module` in this context isn't the same object that's provided
|
|
by the [module wrapper][]. To access it, require the `Module` module:
|
|
|
|
```mjs
|
|
// module.mjs
|
|
// In an ECMAScript module
|
|
import { builtinModules as builtin } from 'node:module';
|
|
```
|
|
|
|
```cjs
|
|
// module.cjs
|
|
// In a CommonJS module
|
|
const builtin = require('node:module').builtinModules;
|
|
```
|
|
|
|
### `module.createRequire(filename)`
|
|
|
|
<!-- YAML
|
|
added: v12.2.0
|
|
-->
|
|
|
|
* `filename` {string|URL} Filename to be used to construct the require
|
|
function. Must be a file URL object, file URL string, or absolute path
|
|
string.
|
|
* Returns: {require} Require function
|
|
|
|
```mjs
|
|
import { createRequire } from 'node:module';
|
|
const require = createRequire(import.meta.url);
|
|
|
|
// sibling-module.js is a CommonJS module.
|
|
const siblingModule = require('./sibling-module');
|
|
```
|
|
|
|
### `module.findPackageJSON(specifier[, base])`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.2.0
|
|
- v22.14.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active Development
|
|
|
|
* `specifier` {string|URL} The specifier for the module whose `package.json` to
|
|
retrieve. When passing a _bare specifier_, the `package.json` at the root of
|
|
the package is returned. When passing a _relative specifier_ or an _absolute specifier_,
|
|
the closest parent `package.json` is returned.
|
|
* `base` {string|URL} The absolute location (`file:` URL string or FS path) of the
|
|
containing module. For CJS, use `__filename` (not `__dirname`!); for ESM, use
|
|
`import.meta.url`. You do not need to pass it if `specifier` is an `absolute specifier`.
|
|
* Returns: {string|undefined} A path if the `package.json` is found. When `specifier`
|
|
is a package, the package's root `package.json`; when a relative or unresolved, the closest
|
|
`package.json` to the `specifier`.
|
|
|
|
> **Caveat**: Do not use this to try to determine module format. There are many things affecting
|
|
> that determination; the `type` field of package.json is the _least_ definitive (ex file extension
|
|
> supersedes it, and a loader hook supersedes that).
|
|
|
|
> **Caveat**: This currently leverages only the built-in default resolver; if
|
|
> [`resolve` customization hooks][resolve hook] are registered, they will not affect the resolution.
|
|
> This may change in the future.
|
|
|
|
```text
|
|
/path/to/project
|
|
├ packages/
|
|
├ bar/
|
|
├ bar.js
|
|
└ package.json // name = '@foo/bar'
|
|
└ qux/
|
|
├ node_modules/
|
|
└ some-package/
|
|
└ package.json // name = 'some-package'
|
|
├ qux.js
|
|
└ package.json // name = '@foo/qux'
|
|
├ main.js
|
|
└ package.json // name = '@foo'
|
|
```
|
|
|
|
```mjs
|
|
// /path/to/project/packages/bar/bar.js
|
|
import { findPackageJSON } from 'node:module';
|
|
|
|
findPackageJSON('..', import.meta.url);
|
|
// '/path/to/project/package.json'
|
|
// Same result when passing an absolute specifier instead:
|
|
findPackageJSON(new URL('../', import.meta.url));
|
|
findPackageJSON(import.meta.resolve('../'));
|
|
|
|
findPackageJSON('some-package', import.meta.url);
|
|
// '/path/to/project/packages/bar/node_modules/some-package/package.json'
|
|
// When passing an absolute specifier, you might get a different result if the
|
|
// resolved module is inside a subfolder that has nested `package.json`.
|
|
findPackageJSON(import.meta.resolve('some-package'));
|
|
// '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json'
|
|
|
|
findPackageJSON('@foo/qux', import.meta.url);
|
|
// '/path/to/project/packages/qux/package.json'
|
|
```
|
|
|
|
```cjs
|
|
// /path/to/project/packages/bar/bar.js
|
|
const { findPackageJSON } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
const path = require('node:path');
|
|
|
|
findPackageJSON('..', __filename);
|
|
// '/path/to/project/package.json'
|
|
// Same result when passing an absolute specifier instead:
|
|
findPackageJSON(pathToFileURL(path.join(__dirname, '..')));
|
|
|
|
findPackageJSON('some-package', __filename);
|
|
// '/path/to/project/packages/bar/node_modules/some-package/package.json'
|
|
// When passing an absolute specifier, you might get a different result if the
|
|
// resolved module is inside a subfolder that has nested `package.json`.
|
|
findPackageJSON(pathToFileURL(require.resolve('some-package')));
|
|
// '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json'
|
|
|
|
findPackageJSON('@foo/qux', __filename);
|
|
// '/path/to/project/packages/qux/package.json'
|
|
```
|
|
|
|
### `module.isBuiltin(moduleName)`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v18.6.0
|
|
- v16.17.0
|
|
-->
|
|
|
|
* `moduleName` {string} name of the module
|
|
* Returns: {boolean} returns true if the module is builtin else returns false
|
|
|
|
```mjs
|
|
import { isBuiltin } from 'node:module';
|
|
isBuiltin('node:fs'); // true
|
|
isBuiltin('fs'); // true
|
|
isBuiltin('wss'); // false
|
|
```
|
|
|
|
### `module.register(specifier[, parentURL][, options])`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v20.6.0
|
|
- v18.19.0
|
|
changes:
|
|
- version:
|
|
- v23.6.1
|
|
- v22.13.1
|
|
- v20.18.2
|
|
pr-url: https://github.com/nodejs-private/node-private/pull/629
|
|
description: Using this feature with the permission model enabled requires
|
|
passing `--allow-worker`.
|
|
- version:
|
|
- v20.8.0
|
|
- v18.19.0
|
|
pr-url: https://github.com/nodejs/node/pull/49655
|
|
description: Add support for WHATWG URL instances.
|
|
-->
|
|
|
|
> Stability: 1.2 - Release candidate
|
|
|
|
* `specifier` {string|URL} Customization hooks to be registered; this should be
|
|
the same string that would be passed to `import()`, except that if it is
|
|
relative, it is resolved relative to `parentURL`.
|
|
* `parentURL` {string|URL} If you want to resolve `specifier` relative to a base
|
|
URL, such as `import.meta.url`, you can pass that URL here. **Default:**
|
|
`'data:'`
|
|
* `options` {Object}
|
|
* `parentURL` {string|URL} If you want to resolve `specifier` relative to a
|
|
base URL, such as `import.meta.url`, you can pass that URL here. This
|
|
property is ignored if the `parentURL` is supplied as the second argument.
|
|
**Default:** `'data:'`
|
|
* `data` {any} Any arbitrary, cloneable JavaScript value to pass into the
|
|
[`initialize`][] hook.
|
|
* `transferList` {Object\[]} [transferable objects][] to be passed into the
|
|
`initialize` hook.
|
|
|
|
Register a module that exports [hooks][] that customize Node.js module
|
|
resolution and loading behavior. See [Customization hooks][].
|
|
|
|
This feature requires `--allow-worker` if used with the [Permission Model][].
|
|
|
|
### `module.registerHooks(options)`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.5.0
|
|
- v22.15.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active development
|
|
|
|
* `options` {Object}
|
|
* `load` {Function|undefined} See [load hook][]. **Default:** `undefined`.
|
|
* `resolve` {Function|undefined} See [resolve hook][]. **Default:** `undefined`.
|
|
|
|
Register [hooks][] that customize Node.js module resolution and loading behavior.
|
|
See [Customization hooks][].
|
|
|
|
### `module.stripTypeScriptTypes(code[, options])`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.2.0
|
|
- v22.13.0
|
|
-->
|
|
|
|
> Stability: 1.2 - Release candidate
|
|
|
|
* `code` {string} The code to strip type annotations from.
|
|
* `options` {Object}
|
|
* `mode` {string} **Default:** `'strip'`. Possible values are:
|
|
* `'strip'` Only strip type annotations without performing the transformation of TypeScript features.
|
|
* `'transform'` Strip type annotations and transform TypeScript features to JavaScript.
|
|
* `sourceMap` {boolean} **Default:** `false`. Only when `mode` is `'transform'`, if `true`, a source map
|
|
will be generated for the transformed code.
|
|
* `sourceUrl` {string} Specifies the source url used in the source map.
|
|
* Returns: {string} The code with type annotations stripped.
|
|
`module.stripTypeScriptTypes()` removes type annotations from TypeScript code. It
|
|
can be used to strip type annotations from TypeScript code before running it
|
|
with `vm.runInContext()` or `vm.compileFunction()`.
|
|
By default, it will throw an error if the code contains TypeScript features
|
|
that require transformation such as `Enums`,
|
|
see [type-stripping][] for more information.
|
|
When mode is `'transform'`, it also transforms TypeScript features to JavaScript,
|
|
see [transform TypeScript features][] for more information.
|
|
When mode is `'strip'`, source maps are not generated, because locations are preserved.
|
|
If `sourceMap` is provided, when mode is `'strip'`, an error will be thrown.
|
|
|
|
_WARNING_: The output of this function should not be considered stable across Node.js versions,
|
|
due to changes in the TypeScript parser.
|
|
|
|
```mjs
|
|
import { stripTypeScriptTypes } from 'node:module';
|
|
const code = 'const a: number = 1;';
|
|
const strippedCode = stripTypeScriptTypes(code);
|
|
console.log(strippedCode);
|
|
// Prints: const a = 1;
|
|
```
|
|
|
|
```cjs
|
|
const { stripTypeScriptTypes } = require('node:module');
|
|
const code = 'const a: number = 1;';
|
|
const strippedCode = stripTypeScriptTypes(code);
|
|
console.log(strippedCode);
|
|
// Prints: const a = 1;
|
|
```
|
|
|
|
If `sourceUrl` is provided, it will be used appended as a comment at the end of the output:
|
|
|
|
```mjs
|
|
import { stripTypeScriptTypes } from 'node:module';
|
|
const code = 'const a: number = 1;';
|
|
const strippedCode = stripTypeScriptTypes(code, { mode: 'strip', sourceUrl: 'source.ts' });
|
|
console.log(strippedCode);
|
|
// Prints: const a = 1\n\n//# sourceURL=source.ts;
|
|
```
|
|
|
|
```cjs
|
|
const { stripTypeScriptTypes } = require('node:module');
|
|
const code = 'const a: number = 1;';
|
|
const strippedCode = stripTypeScriptTypes(code, { mode: 'strip', sourceUrl: 'source.ts' });
|
|
console.log(strippedCode);
|
|
// Prints: const a = 1\n\n//# sourceURL=source.ts;
|
|
```
|
|
|
|
When `mode` is `'transform'`, the code is transformed to JavaScript:
|
|
|
|
```mjs
|
|
import { stripTypeScriptTypes } from 'node:module';
|
|
const code = `
|
|
namespace MathUtil {
|
|
export const add = (a: number, b: number) => a + b;
|
|
}`;
|
|
const strippedCode = stripTypeScriptTypes(code, { mode: 'transform', sourceMap: true });
|
|
console.log(strippedCode);
|
|
// Prints:
|
|
// var MathUtil;
|
|
// (function(MathUtil) {
|
|
// MathUtil.add = (a, b)=>a + b;
|
|
// })(MathUtil || (MathUtil = {}));
|
|
// # sourceMappingURL=data:application/json;base64, ...
|
|
```
|
|
|
|
```cjs
|
|
const { stripTypeScriptTypes } = require('node:module');
|
|
const code = `
|
|
namespace MathUtil {
|
|
export const add = (a: number, b: number) => a + b;
|
|
}`;
|
|
const strippedCode = stripTypeScriptTypes(code, { mode: 'transform', sourceMap: true });
|
|
console.log(strippedCode);
|
|
// Prints:
|
|
// var MathUtil;
|
|
// (function(MathUtil) {
|
|
// MathUtil.add = (a, b)=>a + b;
|
|
// })(MathUtil || (MathUtil = {}));
|
|
// # sourceMappingURL=data:application/json;base64, ...
|
|
```
|
|
|
|
### `module.syncBuiltinESMExports()`
|
|
|
|
<!-- YAML
|
|
added: v12.12.0
|
|
-->
|
|
|
|
The `module.syncBuiltinESMExports()` method updates all the live bindings for
|
|
builtin [ES Modules][] to match the properties of the [CommonJS][] exports. It
|
|
does not add or remove exported names from the [ES Modules][].
|
|
|
|
```js
|
|
const fs = require('node:fs');
|
|
const assert = require('node:assert');
|
|
const { syncBuiltinESMExports } = require('node:module');
|
|
|
|
fs.readFile = newAPI;
|
|
|
|
delete fs.readFileSync;
|
|
|
|
function newAPI() {
|
|
// ...
|
|
}
|
|
|
|
fs.newAPI = newAPI;
|
|
|
|
syncBuiltinESMExports();
|
|
|
|
import('node:fs').then((esmFS) => {
|
|
// It syncs the existing readFile property with the new value
|
|
assert.strictEqual(esmFS.readFile, newAPI);
|
|
// readFileSync has been deleted from the required fs
|
|
assert.strictEqual('readFileSync' in fs, false);
|
|
// syncBuiltinESMExports() does not remove readFileSync from esmFS
|
|
assert.strictEqual('readFileSync' in esmFS, true);
|
|
// syncBuiltinESMExports() does not add names
|
|
assert.strictEqual(esmFS.newAPI, undefined);
|
|
});
|
|
```
|
|
|
|
## Module compile cache
|
|
|
|
<!-- YAML
|
|
added: v22.1.0
|
|
changes:
|
|
- version: v22.8.0
|
|
pr-url: https://github.com/nodejs/node/pull/54501
|
|
description: add initial JavaScript APIs for runtime access.
|
|
-->
|
|
|
|
The module compile cache can be enabled either using the [`module.enableCompileCache()`][]
|
|
method or the [`NODE_COMPILE_CACHE=dir`][] environment variable. After it is enabled,
|
|
whenever Node.js compiles a CommonJS or a ECMAScript Module, it will use on-disk
|
|
[V8 code cache][] persisted in the specified directory to speed up the compilation.
|
|
This may slow down the first load of a module graph, but subsequent loads of the same module
|
|
graph may get a significant speedup if the contents of the modules do not change.
|
|
|
|
To clean up the generated compile cache on disk, simply remove the cache directory. The cache
|
|
directory will be recreated the next time the same directory is used for for compile cache
|
|
storage. To avoid filling up the disk with stale cache, it is recommended to use a directory
|
|
under the [`os.tmpdir()`][]. If the compile cache is enabled by a call to
|
|
[`module.enableCompileCache()`][] without specifying the directory, Node.js will use
|
|
the [`NODE_COMPILE_CACHE=dir`][] environment variable if it's set, or defaults
|
|
to `path.join(os.tmpdir(), 'node-compile-cache')` otherwise. To locate the compile cache
|
|
directory used by a running Node.js instance, use [`module.getCompileCacheDir()`][].
|
|
|
|
Currently when using the compile cache with [V8 JavaScript code coverage][], the
|
|
coverage being collected by V8 may be less precise in functions that are
|
|
deserialized from the code cache. It's recommended to turn this off when
|
|
running tests to generate precise coverage.
|
|
|
|
The enabled module compile cache can be disabled by the [`NODE_DISABLE_COMPILE_CACHE=1`][]
|
|
environment variable. This can be useful when the compile cache leads to unexpected or
|
|
undesired behaviors (e.g. less precise test coverage).
|
|
|
|
Compilation cache generated by one version of Node.js can not be reused by a different
|
|
version of Node.js. Cache generated by different versions of Node.js will be stored
|
|
separately if the same base directory is used to persist the cache, so they can co-exist.
|
|
|
|
At the moment, when the compile cache is enabled and a module is loaded afresh, the
|
|
code cache is generated from the compiled code immediately, but will only be written
|
|
to disk when the Node.js instance is about to exit. This is subject to change. The
|
|
[`module.flushCompileCache()`][] method can be used to ensure the accumulated code cache
|
|
is flushed to disk in case the application wants to spawn other Node.js instances
|
|
and let them share the cache long before the parent exits.
|
|
|
|
### `module.constants.compileCacheStatus`
|
|
|
|
<!-- YAML
|
|
added: v22.8.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active Development
|
|
|
|
The following constants are returned as the `status` field in the object returned by
|
|
[`module.enableCompileCache()`][] to indicate the result of the attempt to enable the
|
|
[module compile cache][].
|
|
|
|
<table>
|
|
<tr>
|
|
<th>Constant</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
<tr>
|
|
<td><code>ENABLED</code></td>
|
|
<td>
|
|
Node.js has enabled the compile cache successfully. The directory used to store the
|
|
compile cache will be returned in the <code>directory</code> field in the
|
|
returned object.
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>ALREADY_ENABLED</code></td>
|
|
<td>
|
|
The compile cache has already been enabled before, either by a previous call to
|
|
<code>module.enableCompileCache()</code>, or by the <code>NODE_COMPILE_CACHE=dir</code>
|
|
environment variable. The directory used to store the
|
|
compile cache will be returned in the <code>directory</code> field in the
|
|
returned object.
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>FAILED</code></td>
|
|
<td>
|
|
Node.js fails to enable the compile cache. This can be caused by the lack of
|
|
permission to use the specified directory, or various kinds of file system errors.
|
|
The detail of the failure will be returned in the <code>message</code> field in the
|
|
returned object.
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>DISABLED</code></td>
|
|
<td>
|
|
Node.js cannot enable the compile cache because the environment variable
|
|
<code>NODE_DISABLE_COMPILE_CACHE=1</code> has been set.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
### `module.enableCompileCache([cacheDir])`
|
|
|
|
<!-- YAML
|
|
added: v22.8.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active Development
|
|
|
|
* `cacheDir` {string|undefined} Optional path to specify the directory where the compile cache
|
|
will be stored/retrieved.
|
|
* Returns: {Object}
|
|
* `status` {integer} One of the [`module.constants.compileCacheStatus`][]
|
|
* `message` {string|undefined} If Node.js cannot enable the compile cache, this contains
|
|
the error message. Only set if `status` is `module.constants.compileCacheStatus.FAILED`.
|
|
* `directory` {string|undefined} If the compile cache is enabled, this contains the directory
|
|
where the compile cache is stored. Only set if `status` is
|
|
`module.constants.compileCacheStatus.ENABLED` or
|
|
`module.constants.compileCacheStatus.ALREADY_ENABLED`.
|
|
|
|
Enable [module compile cache][] in the current Node.js instance.
|
|
|
|
If `cacheDir` is not specified, Node.js will either use the directory specified by the
|
|
[`NODE_COMPILE_CACHE=dir`][] environment variable if it's set, or use
|
|
`path.join(os.tmpdir(), 'node-compile-cache')` otherwise. For general use cases, it's
|
|
recommended to call `module.enableCompileCache()` without specifying the `cacheDir`,
|
|
so that the directory can be overridden by the `NODE_COMPILE_CACHE` environment
|
|
variable when necessary.
|
|
|
|
Since compile cache is supposed to be a quiet optimization that is not required for the
|
|
application to be functional, this method is designed to not throw any exception when the
|
|
compile cache cannot be enabled. Instead, it will return an object containing an error
|
|
message in the `message` field to aid debugging.
|
|
If compile cache is enabled successfully, the `directory` field in the returned object
|
|
contains the path to the directory where the compile cache is stored. The `status`
|
|
field in the returned object would be one of the `module.constants.compileCacheStatus`
|
|
values to indicate the result of the attempt to enable the [module compile cache][].
|
|
|
|
This method only affects the current Node.js instance. To enable it in child worker threads,
|
|
either call this method in child worker threads too, or set the
|
|
`process.env.NODE_COMPILE_CACHE` value to compile cache directory so the behavior can
|
|
be inherited into the child workers. The directory can be obtained either from the
|
|
`directory` field returned by this method, or with [`module.getCompileCacheDir()`][].
|
|
|
|
### `module.flushCompileCache()`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.0.0
|
|
- v22.10.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active Development
|
|
|
|
Flush the [module compile cache][] accumulated from modules already loaded
|
|
in the current Node.js instance to disk. This returns after all the flushing
|
|
file system operations come to an end, no matter they succeed or not. If there
|
|
are any errors, this will fail silently, since compile cache misses should not
|
|
interfere with the actual operation of the application.
|
|
|
|
### `module.getCompileCacheDir()`
|
|
|
|
<!-- YAML
|
|
added: v22.8.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active Development
|
|
|
|
* Returns: {string|undefined} Path to the [module compile cache][] directory if it is enabled,
|
|
or `undefined` otherwise.
|
|
|
|
<i id="module_customization_hooks"></i>
|
|
|
|
## Customization Hooks
|
|
|
|
<!-- YAML
|
|
added: v8.8.0
|
|
changes:
|
|
- version:
|
|
- v23.5.0
|
|
- v22.15.0
|
|
pr-url: https://github.com/nodejs/node/pull/55698
|
|
description: Add support for synchronous and in-thread hooks.
|
|
- version:
|
|
- v20.6.0
|
|
- v18.19.0
|
|
pr-url: https://github.com/nodejs/node/pull/48842
|
|
description: Added `initialize` hook to replace `globalPreload`.
|
|
- version:
|
|
- v18.6.0
|
|
- v16.17.0
|
|
pr-url: https://github.com/nodejs/node/pull/42623
|
|
description: Add support for chaining loaders.
|
|
- version: v16.12.0
|
|
pr-url: https://github.com/nodejs/node/pull/37468
|
|
description: Removed `getFormat`, `getSource`, `transformSource`, and
|
|
`globalPreload`; added `load` hook and `getGlobalPreload` hook.
|
|
-->
|
|
|
|
<!-- type=misc -->
|
|
|
|
> Stability: 1.2 - Release candidate (asynchronous version)
|
|
> Stability: 1.1 - Active development (synchronous version)
|
|
|
|
There are two types of module customization hooks that are currently supported:
|
|
|
|
1. `module.register(specifier[, parentURL][, options])` which takes a module that
|
|
exports asynchronous hook functions. The functions are run on a separate loader
|
|
thread.
|
|
2. `module.registerHooks(options)` which takes synchronous hook functions that are
|
|
run directly on the thread where the module is loaded.
|
|
|
|
<i id="enabling_module_customization_hooks"></i>
|
|
|
|
### Enabling
|
|
|
|
Module resolution and loading can be customized by:
|
|
|
|
1. Registering a file which exports a set of asynchronous hook functions, using the
|
|
[`register`][] method from `node:module`,
|
|
2. Registering a set of synchronous hook functions using the [`registerHooks`][] method
|
|
from `node:module`.
|
|
|
|
The hooks can be registered before the application code is run by using the
|
|
[`--import`][] or [`--require`][] flag:
|
|
|
|
```bash
|
|
node --import ./register-hooks.js ./my-app.js
|
|
node --require ./register-hooks.js ./my-app.js
|
|
```
|
|
|
|
```mjs
|
|
// register-hooks.js
|
|
// This file can only be require()-ed if it doesn't contain top-level await.
|
|
// Use module.register() to register asynchronous hooks in a dedicated thread.
|
|
import { register } from 'node:module';
|
|
register('./hooks.mjs', import.meta.url);
|
|
```
|
|
|
|
```cjs
|
|
// register-hooks.js
|
|
const { register } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
// Use module.register() to register asynchronous hooks in a dedicated thread.
|
|
register('./hooks.mjs', pathToFileURL(__filename));
|
|
```
|
|
|
|
```mjs
|
|
// Use module.registerHooks() to register synchronous hooks in the main thread.
|
|
import { registerHooks } from 'node:module';
|
|
registerHooks({
|
|
resolve(specifier, context, nextResolve) { /* implementation */ },
|
|
load(url, context, nextLoad) { /* implementation */ },
|
|
});
|
|
```
|
|
|
|
```cjs
|
|
// Use module.registerHooks() to register synchronous hooks in the main thread.
|
|
const { registerHooks } = require('node:module');
|
|
registerHooks({
|
|
resolve(specifier, context, nextResolve) { /* implementation */ },
|
|
load(url, context, nextLoad) { /* implementation */ },
|
|
});
|
|
```
|
|
|
|
The file passed to `--import` or `--require` can also be an export from a dependency:
|
|
|
|
```bash
|
|
node --import some-package/register ./my-app.js
|
|
node --require some-package/register ./my-app.js
|
|
```
|
|
|
|
Where `some-package` has an [`"exports"`][] field defining the `/register`
|
|
export to map to a file that calls `register()`, like the following `register-hooks.js`
|
|
example.
|
|
|
|
Using `--import` or `--require` ensures that the hooks are registered before any
|
|
application files are imported, including the entry point of the application and for
|
|
any worker threads by default as well.
|
|
|
|
Alternatively, `register()` and `registerHooks()` can be called from the entry point,
|
|
though dynamic `import()` must be used for any ESM code that should be run after the hooks
|
|
are registered.
|
|
|
|
```mjs
|
|
import { register } from 'node:module';
|
|
|
|
register('http-to-https', import.meta.url);
|
|
|
|
// Because this is a dynamic `import()`, the `http-to-https` hooks will run
|
|
// to handle `./my-app.js` and any other files it imports or requires.
|
|
await import('./my-app.js');
|
|
```
|
|
|
|
```cjs
|
|
const { register } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
|
|
register('http-to-https', pathToFileURL(__filename));
|
|
|
|
// Because this is a dynamic `import()`, the `http-to-https` hooks will run
|
|
// to handle `./my-app.js` and any other files it imports or requires.
|
|
import('./my-app.js');
|
|
```
|
|
|
|
Customization hooks will run for any modules loaded later than the registration
|
|
and the modules they reference via `import` and the built-in `require`.
|
|
`require` function created by users using `module.createRequire()` can only be
|
|
customized by the synchronous hooks.
|
|
|
|
In this example, we are registering the `http-to-https` hooks, but they will
|
|
only be available for subsequently imported modules — in this case, `my-app.js`
|
|
and anything it references via `import` or built-in `require` in CommonJS dependencies.
|
|
|
|
If the `import('./my-app.js')` had instead been a static `import './my-app.js'`, the
|
|
app would have _already_ been loaded **before** the `http-to-https` hooks were
|
|
registered. This due to the ES modules specification, where static imports are
|
|
evaluated from the leaves of the tree first, then back to the trunk. There can
|
|
be static imports _within_ `my-app.js`, which will not be evaluated until
|
|
`my-app.js` is dynamically imported.
|
|
|
|
If synchronous hooks are used, both `import`, `require` and user `require` created
|
|
using `createRequire()` are supported.
|
|
|
|
```mjs
|
|
import { registerHooks, createRequire } from 'node:module';
|
|
|
|
registerHooks({ /* implementation of synchronous hooks */ });
|
|
|
|
const require = createRequire(import.meta.url);
|
|
|
|
// The synchronous hooks affect import, require() and user require() function
|
|
// created through createRequire().
|
|
await import('./my-app.js');
|
|
require('./my-app-2.js');
|
|
```
|
|
|
|
```cjs
|
|
const { register, registerHooks } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
|
|
registerHooks({ /* implementation of synchronous hooks */ });
|
|
|
|
const userRequire = createRequire(__filename);
|
|
|
|
// The synchronous hooks affect import, require() and user require() function
|
|
// created through createRequire().
|
|
import('./my-app.js');
|
|
require('./my-app-2.js');
|
|
userRequire('./my-app-3.js');
|
|
```
|
|
|
|
Finally, if all you want to do is register hooks before your app runs and you
|
|
don't want to create a separate file for that purpose, you can pass a `data:`
|
|
URL to `--import`:
|
|
|
|
```bash
|
|
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("http-to-https", pathToFileURL("./"));' ./my-app.js
|
|
```
|
|
|
|
### Chaining
|
|
|
|
It's possible to call `register` more than once:
|
|
|
|
```mjs
|
|
// entrypoint.mjs
|
|
import { register } from 'node:module';
|
|
|
|
register('./foo.mjs', import.meta.url);
|
|
register('./bar.mjs', import.meta.url);
|
|
await import('./my-app.mjs');
|
|
```
|
|
|
|
```cjs
|
|
// entrypoint.cjs
|
|
const { register } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
|
|
const parentURL = pathToFileURL(__filename);
|
|
register('./foo.mjs', parentURL);
|
|
register('./bar.mjs', parentURL);
|
|
import('./my-app.mjs');
|
|
```
|
|
|
|
In this example, the registered hooks will form chains. These chains run
|
|
last-in, first out (LIFO). If both `foo.mjs` and `bar.mjs` define a `resolve`
|
|
hook, they will be called like so (note the right-to-left):
|
|
node's default ← `./foo.mjs` ← `./bar.mjs`
|
|
(starting with `./bar.mjs`, then `./foo.mjs`, then the Node.js default).
|
|
The same applies to all the other hooks.
|
|
|
|
The registered hooks also affect `register` itself. In this example,
|
|
`bar.mjs` will be resolved and loaded via the hooks registered by `foo.mjs`
|
|
(because `foo`'s hooks will have already been added to the chain). This allows
|
|
for things like writing hooks in non-JavaScript languages, so long as
|
|
earlier registered hooks transpile into JavaScript.
|
|
|
|
The `register` method cannot be called from within the module that defines the
|
|
hooks.
|
|
|
|
Chaining of `registerHooks` work similarly. If synchronous and asynchronous
|
|
hooks are mixed, the synchronous hooks are always run first before the asynchronous
|
|
hooks start running, that is, in the last synchronous hook being run, its next
|
|
hook includes invocation of the asynchronous hooks.
|
|
|
|
```mjs
|
|
// entrypoint.mjs
|
|
import { registerHooks } from 'node:module';
|
|
|
|
const hook1 = { /* implementation of hooks */ };
|
|
const hook2 = { /* implementation of hooks */ };
|
|
// hook2 run before hook1.
|
|
registerHooks(hook1);
|
|
registerHooks(hook2);
|
|
```
|
|
|
|
```cjs
|
|
// entrypoint.cjs
|
|
const { registerHooks } = require('node:module');
|
|
|
|
const hook1 = { /* implementation of hooks */ };
|
|
const hook2 = { /* implementation of hooks */ };
|
|
// hook2 run before hook1.
|
|
registerHooks(hook1);
|
|
registerHooks(hook2);
|
|
```
|
|
|
|
### Communication with module customization hooks
|
|
|
|
Asynchronous hooks run on a dedicated thread, separate from the main
|
|
thread that runs application code. This means mutating global variables won't
|
|
affect the other thread(s), and message channels must be used to communicate
|
|
between the threads.
|
|
|
|
The `register` method can be used to pass data to an [`initialize`][] hook. The
|
|
data passed to the hook may include transferable objects like ports.
|
|
|
|
```mjs
|
|
import { register } from 'node:module';
|
|
import { MessageChannel } from 'node:worker_threads';
|
|
|
|
// This example demonstrates how a message channel can be used to
|
|
// communicate with the hooks, by sending `port2` to the hooks.
|
|
const { port1, port2 } = new MessageChannel();
|
|
|
|
port1.on('message', (msg) => {
|
|
console.log(msg);
|
|
});
|
|
port1.unref();
|
|
|
|
register('./my-hooks.mjs', {
|
|
parentURL: import.meta.url,
|
|
data: { number: 1, port: port2 },
|
|
transferList: [port2],
|
|
});
|
|
```
|
|
|
|
```cjs
|
|
const { register } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
const { MessageChannel } = require('node:worker_threads');
|
|
|
|
// This example showcases how a message channel can be used to
|
|
// communicate with the hooks, by sending `port2` to the hooks.
|
|
const { port1, port2 } = new MessageChannel();
|
|
|
|
port1.on('message', (msg) => {
|
|
console.log(msg);
|
|
});
|
|
port1.unref();
|
|
|
|
register('./my-hooks.mjs', {
|
|
parentURL: pathToFileURL(__filename),
|
|
data: { number: 1, port: port2 },
|
|
transferList: [port2],
|
|
});
|
|
```
|
|
|
|
Synchronous module hooks are run on the same thread where the application code is
|
|
run. They can directly mutate the globals of the context accessed by the main thread.
|
|
|
|
### Hooks
|
|
|
|
#### Asynchronous hooks accepted by `module.register()`
|
|
|
|
The [`register`][] method can be used to register a module that exports a set of
|
|
hooks. The hooks are functions that are called by Node.js to customize the
|
|
module resolution and loading process. The exported functions must have specific
|
|
names and signatures, and they must be exported as named exports.
|
|
|
|
```mjs
|
|
export async function initialize({ number, port }) {
|
|
// Receives data from `register`.
|
|
}
|
|
|
|
export async function resolve(specifier, context, nextResolve) {
|
|
// Take an `import` or `require` specifier and resolve it to a URL.
|
|
}
|
|
|
|
export async function load(url, context, nextLoad) {
|
|
// Take a resolved URL and return the source code to be evaluated.
|
|
}
|
|
```
|
|
|
|
Asynchronous hooks are run in a separate thread, isolated from the main thread where
|
|
application code runs. That means it is a different [realm][]. The hooks thread
|
|
may be terminated by the main thread at any time, so do not depend on
|
|
asynchronous operations (like `console.log`) to complete. They are inherited into
|
|
child workers by default.
|
|
|
|
#### Synchronous hooks accepted by `module.registerHooks()`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.5.0
|
|
- v22.15.0
|
|
-->
|
|
|
|
> Stability: 1.1 - Active development
|
|
|
|
The `module.registerHooks()` method accepts synchronous hook functions.
|
|
`initialize()` is not supported nor necessary, as the hook implementer
|
|
can simply run the initialization code directly before the call to
|
|
`module.registerHooks()`.
|
|
|
|
```mjs
|
|
function resolve(specifier, context, nextResolve) {
|
|
// Take an `import` or `require` specifier and resolve it to a URL.
|
|
}
|
|
|
|
function load(url, context, nextLoad) {
|
|
// Take a resolved URL and return the source code to be evaluated.
|
|
}
|
|
```
|
|
|
|
Synchronous hooks are run in the same thread and the same [realm][] where the modules
|
|
are loaded. Unlike the asynchronous hooks they are not inherited into child worker
|
|
threads by default, though if the hooks are registered using a file preloaded by
|
|
[`--import`][] or [`--require`][], child worker threads can inherit the preloaded scripts
|
|
via `process.execArgv` inheritance. See [the documentation of `Worker`][] for detail.
|
|
|
|
In synchronous hooks, users can expect `console.log()` to complete in the same way that
|
|
they expect `console.log()` in module code to complete.
|
|
|
|
#### Conventions of hooks
|
|
|
|
Hooks are part of a [chain][], even if that chain consists of only one
|
|
custom (user-provided) hook and the default hook, which is always present. Hook
|
|
functions nest: each one must always return a plain object, and chaining happens
|
|
as a result of each function calling `next<hookName>()`, which is a reference to
|
|
the subsequent loader's hook (in LIFO order).
|
|
|
|
A hook that returns a value lacking a required property triggers an exception. A
|
|
hook that returns without calling `next<hookName>()` _and_ without returning
|
|
`shortCircuit: true` also triggers an exception. These errors are to help
|
|
prevent unintentional breaks in the chain. Return `shortCircuit: true` from a
|
|
hook to signal that the chain is intentionally ending at your hook.
|
|
|
|
#### `initialize()`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v20.6.0
|
|
- v18.19.0
|
|
-->
|
|
|
|
> Stability: 1.2 - Release candidate
|
|
|
|
* `data` {any} The data from `register(loader, import.meta.url, { data })`.
|
|
|
|
The `initialize` hook is only accepted by [`register`][]. `registerHooks()` does
|
|
not support nor need it since initialization done for synchronous hooks can be run
|
|
directly before the call to `registerHooks()`.
|
|
|
|
The `initialize` hook provides a way to define a custom function that runs in
|
|
the hooks thread when the hooks module is initialized. Initialization happens
|
|
when the hooks module is registered via [`register`][].
|
|
|
|
This hook can receive data from a [`register`][] invocation, including
|
|
ports and other transferable objects. The return value of `initialize` can be a
|
|
{Promise}, in which case it will be awaited before the main application thread
|
|
execution resumes.
|
|
|
|
Module customization code:
|
|
|
|
```mjs
|
|
// path-to-my-hooks.js
|
|
|
|
export async function initialize({ number, port }) {
|
|
port.postMessage(`increment: ${number + 1}`);
|
|
}
|
|
```
|
|
|
|
Caller code:
|
|
|
|
```mjs
|
|
import assert from 'node:assert';
|
|
import { register } from 'node:module';
|
|
import { MessageChannel } from 'node:worker_threads';
|
|
|
|
// This example showcases how a message channel can be used to communicate
|
|
// between the main (application) thread and the hooks running on the hooks
|
|
// thread, by sending `port2` to the `initialize` hook.
|
|
const { port1, port2 } = new MessageChannel();
|
|
|
|
port1.on('message', (msg) => {
|
|
assert.strictEqual(msg, 'increment: 2');
|
|
});
|
|
port1.unref();
|
|
|
|
register('./path-to-my-hooks.js', {
|
|
parentURL: import.meta.url,
|
|
data: { number: 1, port: port2 },
|
|
transferList: [port2],
|
|
});
|
|
```
|
|
|
|
```cjs
|
|
const assert = require('node:assert');
|
|
const { register } = require('node:module');
|
|
const { pathToFileURL } = require('node:url');
|
|
const { MessageChannel } = require('node:worker_threads');
|
|
|
|
// This example showcases how a message channel can be used to communicate
|
|
// between the main (application) thread and the hooks running on the hooks
|
|
// thread, by sending `port2` to the `initialize` hook.
|
|
const { port1, port2 } = new MessageChannel();
|
|
|
|
port1.on('message', (msg) => {
|
|
assert.strictEqual(msg, 'increment: 2');
|
|
});
|
|
port1.unref();
|
|
|
|
register('./path-to-my-hooks.js', {
|
|
parentURL: pathToFileURL(__filename),
|
|
data: { number: 1, port: port2 },
|
|
transferList: [port2],
|
|
});
|
|
```
|
|
|
|
#### `resolve(specifier, context, nextResolve)`
|
|
|
|
<!-- YAML
|
|
changes:
|
|
- version:
|
|
- v23.5.0
|
|
- v22.15.0
|
|
pr-url: https://github.com/nodejs/node/pull/55698
|
|
description: Add support for synchronous and in-thread hooks.
|
|
- version:
|
|
- v21.0.0
|
|
- v20.10.0
|
|
- v18.19.0
|
|
pr-url: https://github.com/nodejs/node/pull/50140
|
|
description: The property `context.importAssertions` is replaced with
|
|
`context.importAttributes`. Using the old name is still
|
|
supported and will emit an experimental warning.
|
|
- version:
|
|
- v18.6.0
|
|
- v16.17.0
|
|
pr-url: https://github.com/nodejs/node/pull/42623
|
|
description: Add support for chaining resolve hooks. Each hook must either
|
|
call `nextResolve()` or include a `shortCircuit` property set to `true`
|
|
in its return.
|
|
- version:
|
|
- v17.1.0
|
|
- v16.14.0
|
|
pr-url: https://github.com/nodejs/node/pull/40250
|
|
description: Add support for import assertions.
|
|
-->
|
|
|
|
* `specifier` {string}
|
|
* `context` {Object}
|
|
* `conditions` {string\[]} Export conditions of the relevant `package.json`
|
|
* `importAttributes` {Object} An object whose key-value pairs represent the
|
|
attributes for the module to import
|
|
* `parentURL` {string|undefined} The module importing this one, or undefined
|
|
if this is the Node.js entry point
|
|
* `nextResolve` {Function} The subsequent `resolve` hook in the chain, or the
|
|
Node.js default `resolve` hook after the last user-supplied `resolve` hook
|
|
* `specifier` {string}
|
|
* `context` {Object|undefined} When omitted, the defaults are provided. When provided, defaults
|
|
are merged in with preference to the provided properties.
|
|
* Returns: {Object|Promise} The asynchronous version takes either an object containing the
|
|
following properties, or a `Promise` that will resolve to such an object. The
|
|
synchronous version only accepts an object returned synchronously.
|
|
* `format` {string|null|undefined} A hint to the `load` hook (it might be ignored). It can be a
|
|
module format (such as `'commonjs'` or `'module'`) or an arbitrary value like `'css'` or
|
|
`'yaml'`.
|
|
* `importAttributes` {Object|undefined} The import attributes to use when
|
|
caching the module (optional; if excluded the input will be used)
|
|
* `shortCircuit` {undefined|boolean} A signal that this hook intends to
|
|
terminate the chain of `resolve` hooks. **Default:** `false`
|
|
* `url` {string} The absolute URL to which this input resolves
|
|
|
|
> **Warning** In the case of the asynchronous version, despite support for returning
|
|
> promises and async functions, calls to `resolve` may still block the main thread which
|
|
> can impact performance.
|
|
|
|
The `resolve` hook chain is responsible for telling Node.js where to find and
|
|
how to cache a given `import` statement or expression, or `require` call. It can
|
|
optionally return a format (such as `'module'`) as a hint to the `load` hook. If
|
|
a format is specified, the `load` hook is ultimately responsible for providing
|
|
the final `format` value (and it is free to ignore the hint provided by
|
|
`resolve`); if `resolve` provides a `format`, a custom `load` hook is required
|
|
even if only to pass the value to the Node.js default `load` hook.
|
|
|
|
Import type attributes are part of the cache key for saving loaded modules into
|
|
the internal module cache. The `resolve` hook is responsible for returning an
|
|
`importAttributes` object if the module should be cached with different
|
|
attributes than were present in the source code.
|
|
|
|
The `conditions` property in `context` is an array of conditions that will be used
|
|
to match [package exports conditions][Conditional exports] for this resolution
|
|
request. They can be used for looking up conditional mappings elsewhere or to
|
|
modify the list when calling the default resolution logic.
|
|
|
|
The current [package exports conditions][Conditional exports] are always in
|
|
the `context.conditions` array passed into the hook. To guarantee _default
|
|
Node.js module specifier resolution behavior_ when calling `defaultResolve`, the
|
|
`context.conditions` array passed to it _must_ include _all_ elements of the
|
|
`context.conditions` array originally passed into the `resolve` hook.
|
|
|
|
<!-- TODO(joyeecheung): Math.random() is a bit too contrived. At least do a
|
|
find-and-replace mangling on the URLs. -->
|
|
|
|
```mjs
|
|
// Asynchronous version accepted by module.register().
|
|
export async function resolve(specifier, context, nextResolve) {
|
|
const { parentURL = null } = context;
|
|
|
|
if (Math.random() > 0.5) { // Some condition.
|
|
// For some or all specifiers, do some custom logic for resolving.
|
|
// Always return an object of the form {url: <string>}.
|
|
return {
|
|
shortCircuit: true,
|
|
url: parentURL ?
|
|
new URL(specifier, parentURL).href :
|
|
new URL(specifier).href,
|
|
};
|
|
}
|
|
|
|
if (Math.random() < 0.5) { // Another condition.
|
|
// When calling `defaultResolve`, the arguments can be modified. In this
|
|
// case it's adding another value for matching conditional exports.
|
|
return nextResolve(specifier, {
|
|
...context,
|
|
conditions: [...context.conditions, 'another-condition'],
|
|
});
|
|
}
|
|
|
|
// Defer to the next hook in the chain, which would be the
|
|
// Node.js default resolve if this is the last user-specified loader.
|
|
return nextResolve(specifier);
|
|
}
|
|
```
|
|
|
|
```mjs
|
|
// Synchronous version accepted by module.registerHooks().
|
|
function resolve(specifier, context, nextResolve) {
|
|
// Similar to the asynchronous resolve() above, since that one does not have
|
|
// any asynchronous logic.
|
|
}
|
|
```
|
|
|
|
#### `load(url, context, nextLoad)`
|
|
|
|
<!-- YAML
|
|
changes:
|
|
- version:
|
|
- v23.5.0
|
|
- v22.15.0
|
|
pr-url: https://github.com/nodejs/node/pull/55698
|
|
description: Add support for synchronous and in-thread version.
|
|
- version: v20.6.0
|
|
pr-url: https://github.com/nodejs/node/pull/47999
|
|
description: Add support for `source` with format `commonjs`.
|
|
- version:
|
|
- v18.6.0
|
|
- v16.17.0
|
|
pr-url: https://github.com/nodejs/node/pull/42623
|
|
description: Add support for chaining load hooks. Each hook must either
|
|
call `nextLoad()` or include a `shortCircuit` property set to `true` in
|
|
its return.
|
|
-->
|
|
|
|
* `url` {string} The URL returned by the `resolve` chain
|
|
* `context` {Object}
|
|
* `conditions` {string\[]} Export conditions of the relevant `package.json`
|
|
* `format` {string|null|undefined} The format optionally supplied by the
|
|
`resolve` hook chain. This can be any string value as an input; input values do not need to
|
|
conform to the list of acceptable return values described below.
|
|
* `importAttributes` {Object}
|
|
* `nextLoad` {Function} The subsequent `load` hook in the chain, or the
|
|
Node.js default `load` hook after the last user-supplied `load` hook
|
|
* `url` {string}
|
|
* `context` {Object|undefined} When omitted, defaults are provided. When provided, defaults are
|
|
merged in with preference to the provided properties. In the default `nextLoad`, if
|
|
the module pointed to by `url` does not have explicit module type information,
|
|
`context.format` is mandatory.
|
|
<!-- TODO(joyeecheung): make it at least optionally non-mandatory by allowing
|
|
JS-style/TS-style module detection when the format is simply unknown -->
|
|
* Returns: {Object|Promise} The asynchronous version takes either an object containing the
|
|
following properties, or a `Promise` that will resolve to such an object. The
|
|
synchronous version only accepts an object returned synchronously.
|
|
* `format` {string}
|
|
* `shortCircuit` {undefined|boolean} A signal that this hook intends to
|
|
terminate the chain of `load` hooks. **Default:** `false`
|
|
* `source` {string|ArrayBuffer|TypedArray} The source for Node.js to evaluate
|
|
|
|
The `load` hook provides a way to define a custom method of determining how a
|
|
URL should be interpreted, retrieved, and parsed. It is also in charge of
|
|
validating the import attributes.
|
|
|
|
The final value of `format` must be one of the following:
|
|
|
|
| `format` | Description | Acceptable types for `source` returned by `load` |
|
|
| ----------------------- | ----------------------------------------------------- | -------------------------------------------------- |
|
|
| `'addon'` | Load a Node.js addon | {null} |
|
|
| `'builtin'` | Load a Node.js builtin module | {null} |
|
|
| `'commonjs-typescript'` | Load a Node.js CommonJS module with TypeScript syntax | {string\|ArrayBuffer\|TypedArray\|null\|undefined} |
|
|
| `'commonjs'` | Load a Node.js CommonJS module | {string\|ArrayBuffer\|TypedArray\|null\|undefined} |
|
|
| `'json'` | Load a JSON file | {string\|ArrayBuffer\|TypedArray} |
|
|
| `'module-typescript'` | Load an ES module with TypeScript syntax | {string\|ArrayBuffer\|TypedArray} |
|
|
| `'module'` | Load an ES module | {string\|ArrayBuffer\|TypedArray} |
|
|
| `'wasm'` | Load a WebAssembly module | {ArrayBuffer\|TypedArray} |
|
|
|
|
The value of `source` is ignored for type `'builtin'` because currently it is
|
|
not possible to replace the value of a Node.js builtin (core) module.
|
|
|
|
##### Caveat in the asynchronous `load` hook
|
|
|
|
When using the asynchronous `load` hook, omitting vs providing a `source` for
|
|
`'commonjs'` has very different effects:
|
|
|
|
* When a `source` is provided, all `require` calls from this module will be
|
|
processed by the ESM loader with registered `resolve` and `load` hooks; all
|
|
`require.resolve` calls from this module will be processed by the ESM loader
|
|
with registered `resolve` hooks; only a subset of the CommonJS API will be
|
|
available (e.g. no `require.extensions`, no `require.cache`, no
|
|
`require.resolve.paths`) and monkey-patching on the CommonJS module loader
|
|
will not apply.
|
|
* If `source` is undefined or `null`, it will be handled by the CommonJS module
|
|
loader and `require`/`require.resolve` calls will not go through the
|
|
registered hooks. This behavior for nullish `source` is temporary — in the
|
|
future, nullish `source` will not be supported.
|
|
|
|
These caveats do not apply to the synchronous `load` hook, in which case
|
|
the complete set of CommonJS APIs available to the customized CommonJS
|
|
modules, and `require`/`require.resolve` always go through the registered
|
|
hooks.
|
|
|
|
The Node.js internal asynchronous `load` implementation, which is the value of `next` for the
|
|
last hook in the `load` chain, returns `null` for `source` when `format` is
|
|
`'commonjs'` for backward compatibility. Here is an example hook that would
|
|
opt-in to using the non-default behavior:
|
|
|
|
```mjs
|
|
import { readFile } from 'node:fs/promises';
|
|
|
|
// Asynchronous version accepted by module.register(). This fix is not needed
|
|
// for the synchronous version accepted by module.registerHooks().
|
|
export async function load(url, context, nextLoad) {
|
|
const result = await nextLoad(url, context);
|
|
if (result.format === 'commonjs') {
|
|
result.source ??= await readFile(new URL(result.responseURL ?? url));
|
|
}
|
|
return result;
|
|
}
|
|
```
|
|
|
|
This doesn't apply to the synchronous `load` hook either, in which case the
|
|
`source` returned contains source code loaded by the next hook, regardless
|
|
of module format.
|
|
|
|
> **Warning**: The asynchronous `load` hook and namespaced exports from CommonJS
|
|
> modules are incompatible. Attempting to use them together will result in an empty
|
|
> object from the import. This may be addressed in the future. This does not apply
|
|
> to the synchronous `load` hook, in which case exports can be used as usual.
|
|
|
|
> These types all correspond to classes defined in ECMAScript.
|
|
|
|
* The specific {ArrayBuffer} object is a {SharedArrayBuffer}.
|
|
* The specific {TypedArray} object is a {Uint8Array}.
|
|
|
|
If the source value of a text-based format (i.e., `'json'`, `'module'`)
|
|
is not a string, it is converted to a string using [`util.TextDecoder`][].
|
|
|
|
The `load` hook provides a way to define a custom method for retrieving the
|
|
source code of a resolved URL. This would allow a loader to potentially avoid
|
|
reading files from disk. It could also be used to map an unrecognized format to
|
|
a supported one, for example `yaml` to `module`.
|
|
|
|
```mjs
|
|
// Asynchronous version accepted by module.register().
|
|
export async function load(url, context, nextLoad) {
|
|
const { format } = context;
|
|
|
|
if (Math.random() > 0.5) { // Some condition
|
|
/*
|
|
For some or all URLs, do some custom logic for retrieving the source.
|
|
Always return an object of the form {
|
|
format: <string>,
|
|
source: <string|buffer>,
|
|
}.
|
|
*/
|
|
return {
|
|
format,
|
|
shortCircuit: true,
|
|
source: '...',
|
|
};
|
|
}
|
|
|
|
// Defer to the next hook in the chain.
|
|
return nextLoad(url);
|
|
}
|
|
```
|
|
|
|
```mjs
|
|
// Synchronous version accepted by module.registerHooks().
|
|
function load(url, context, nextLoad) {
|
|
// Similar to the asynchronous load() above, since that one does not have
|
|
// any asynchronous logic.
|
|
}
|
|
```
|
|
|
|
In a more advanced scenario, this can also be used to transform an unsupported
|
|
source to a supported one (see [Examples](#examples) below).
|
|
|
|
### Examples
|
|
|
|
The various module customization hooks can be used together to accomplish
|
|
wide-ranging customizations of the Node.js code loading and evaluation
|
|
behaviors.
|
|
|
|
#### Import from HTTPS
|
|
|
|
The hook below registers hooks to enable rudimentary support for such
|
|
specifiers. While this may seem like a significant improvement to Node.js core
|
|
functionality, there are substantial downsides to actually using these hooks:
|
|
performance is much slower than loading files from disk, there is no caching,
|
|
and there is no security.
|
|
|
|
```mjs
|
|
// https-hooks.mjs
|
|
import { get } from 'node:https';
|
|
|
|
export function load(url, context, nextLoad) {
|
|
// For JavaScript to be loaded over the network, we need to fetch and
|
|
// return it.
|
|
if (url.startsWith('https://')) {
|
|
return new Promise((resolve, reject) => {
|
|
get(url, (res) => {
|
|
let data = '';
|
|
res.setEncoding('utf8');
|
|
res.on('data', (chunk) => data += chunk);
|
|
res.on('end', () => resolve({
|
|
// This example assumes all network-provided JavaScript is ES module
|
|
// code.
|
|
format: 'module',
|
|
shortCircuit: true,
|
|
source: data,
|
|
}));
|
|
}).on('error', (err) => reject(err));
|
|
});
|
|
}
|
|
|
|
// Let Node.js handle all other URLs.
|
|
return nextLoad(url);
|
|
}
|
|
```
|
|
|
|
```mjs
|
|
// main.mjs
|
|
import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js';
|
|
|
|
console.log(VERSION);
|
|
```
|
|
|
|
With the preceding hooks module, running
|
|
`node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs`
|
|
prints the current version of CoffeeScript per the module at the URL in
|
|
`main.mjs`.
|
|
|
|
<!-- TODO(joyeecheung): add an example on how to implement it with a fetchSync based on
|
|
workers and Atomics.wait() - or all these examples are too much to be put in the API
|
|
documentation already and should be put into a repository instead? -->
|
|
|
|
#### Transpilation
|
|
|
|
Sources that are in formats Node.js doesn't understand can be converted into
|
|
JavaScript using the [`load` hook][load hook].
|
|
|
|
This is less performant than transpiling source files before running Node.js;
|
|
transpiler hooks should only be used for development and testing purposes.
|
|
|
|
##### Asynchronous version
|
|
|
|
```mjs
|
|
// coffeescript-hooks.mjs
|
|
import { readFile } from 'node:fs/promises';
|
|
import { findPackageJSON } from 'node:module';
|
|
import coffeescript from 'coffeescript';
|
|
|
|
const extensionsRegex = /\.(coffee|litcoffee|coffee\.md)$/;
|
|
|
|
export async function load(url, context, nextLoad) {
|
|
if (extensionsRegex.test(url)) {
|
|
// CoffeeScript files can be either CommonJS or ES modules. Use a custom format
|
|
// to tell Node.js not to detect its module type.
|
|
const { source: rawSource } = await nextLoad(url, { ...context, format: 'coffee' });
|
|
// This hook converts CoffeeScript source code into JavaScript source code
|
|
// for all imported CoffeeScript files.
|
|
const transformedSource = coffeescript.compile(rawSource.toString(), url);
|
|
|
|
// To determine how Node.js would interpret the transpilation result,
|
|
// search up the file system for the nearest parent package.json file
|
|
// and read its "type" field.
|
|
return {
|
|
format: await getPackageType(url),
|
|
shortCircuit: true,
|
|
source: transformedSource,
|
|
};
|
|
}
|
|
|
|
// Let Node.js handle all other URLs.
|
|
return nextLoad(url, context);
|
|
}
|
|
|
|
async function getPackageType(url) {
|
|
// `url` is only a file path during the first iteration when passed the
|
|
// resolved url from the load() hook
|
|
// an actual file path from load() will contain a file extension as it's
|
|
// required by the spec
|
|
// this simple truthy check for whether `url` contains a file extension will
|
|
// work for most projects but does not cover some edge-cases (such as
|
|
// extensionless files or a url ending in a trailing space)
|
|
const pJson = findPackageJSON(url);
|
|
|
|
return readFile(pJson, 'utf8')
|
|
.then(JSON.parse)
|
|
.then((json) => json?.type)
|
|
.catch(() => undefined);
|
|
}
|
|
```
|
|
|
|
##### Synchronous version
|
|
|
|
```mjs
|
|
// coffeescript-sync-hooks.mjs
|
|
import { readFileSync } from 'node:fs';
|
|
import { registerHooks, findPackageJSON } from 'node:module';
|
|
import coffeescript from 'coffeescript';
|
|
|
|
const extensionsRegex = /\.(coffee|litcoffee|coffee\.md)$/;
|
|
|
|
function load(url, context, nextLoad) {
|
|
if (extensionsRegex.test(url)) {
|
|
const { source: rawSource } = nextLoad(url, { ...context, format: 'coffee' });
|
|
const transformedSource = coffeescript.compile(rawSource.toString(), url);
|
|
|
|
return {
|
|
format: getPackageType(url),
|
|
shortCircuit: true,
|
|
source: transformedSource,
|
|
};
|
|
}
|
|
|
|
return nextLoad(url, context);
|
|
}
|
|
|
|
function getPackageType(url) {
|
|
const pJson = findPackageJSON(url);
|
|
if (!pJson) {
|
|
return undefined;
|
|
}
|
|
try {
|
|
const file = readFileSync(pJson, 'utf-8');
|
|
return JSON.parse(file)?.type;
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
registerHooks({ load });
|
|
```
|
|
|
|
#### Running hooks
|
|
|
|
```coffee
|
|
# main.coffee
|
|
import { scream } from './scream.coffee'
|
|
console.log scream 'hello, world'
|
|
|
|
import { version } from 'node:process'
|
|
console.log "Brought to you by Node.js version #{version}"
|
|
```
|
|
|
|
```coffee
|
|
# scream.coffee
|
|
export scream = (str) -> str.toUpperCase()
|
|
```
|
|
|
|
For the sake of running the example, add a `package.json` file containing the
|
|
module type of the CoffeeScript files.
|
|
|
|
```json
|
|
{
|
|
"type": "module"
|
|
}
|
|
```
|
|
|
|
This is only for running the example. In real world loaders, `getPackageType()` must be
|
|
able to return an `format` known to Node.js even in the absence of an explicit type in a
|
|
`package.json`, or otherwise the `nextLoad` call would throw `ERR_UNKNOWN_FILE_EXTENSION`
|
|
(if undefined) or `ERR_UNKNOWN_MODULE_FORMAT` (if it's not a known format listed in
|
|
the [load hook][] documentation).
|
|
|
|
With the preceding hooks modules, running
|
|
`node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./coffeescript-hooks.mjs"));' ./main.coffee`
|
|
or `node --import ./coffeescript-sync-hooks.mjs ./main.coffee`
|
|
causes `main.coffee` to be turned into JavaScript after its source code is
|
|
loaded from disk but before Node.js executes it; and so on for any `.coffee`,
|
|
`.litcoffee` or `.coffee.md` files referenced via `import` statements of any
|
|
loaded file.
|
|
|
|
#### Import maps
|
|
|
|
The previous two examples defined `load` hooks. This is an example of a
|
|
`resolve` hook. This hooks module reads an `import-map.json` file that defines
|
|
which specifiers to override to other URLs (this is a very simplistic
|
|
implementation of a small subset of the "import maps" specification).
|
|
|
|
##### Asynchronous version
|
|
|
|
```mjs
|
|
// import-map-hooks.js
|
|
import fs from 'node:fs/promises';
|
|
|
|
const { imports } = JSON.parse(await fs.readFile('import-map.json'));
|
|
|
|
export async function resolve(specifier, context, nextResolve) {
|
|
if (Object.hasOwn(imports, specifier)) {
|
|
return nextResolve(imports[specifier], context);
|
|
}
|
|
|
|
return nextResolve(specifier, context);
|
|
}
|
|
```
|
|
|
|
##### Synchronous version
|
|
|
|
```mjs
|
|
// import-map-sync-hooks.js
|
|
import fs from 'node:fs/promises';
|
|
import module from 'node:module';
|
|
|
|
const { imports } = JSON.parse(fs.readFileSync('import-map.json', 'utf-8'));
|
|
|
|
function resolve(specifier, context, nextResolve) {
|
|
if (Object.hasOwn(imports, specifier)) {
|
|
return nextResolve(imports[specifier], context);
|
|
}
|
|
|
|
return nextResolve(specifier, context);
|
|
}
|
|
|
|
module.registerHooks({ resolve });
|
|
```
|
|
|
|
##### Using the hooks
|
|
|
|
With these files:
|
|
|
|
```mjs
|
|
// main.js
|
|
import 'a-module';
|
|
```
|
|
|
|
```json
|
|
// import-map.json
|
|
{
|
|
"imports": {
|
|
"a-module": "./some-module.js"
|
|
}
|
|
}
|
|
```
|
|
|
|
```mjs
|
|
// some-module.js
|
|
console.log('some module!');
|
|
```
|
|
|
|
Running `node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./import-map-hooks.js"));' main.js`
|
|
or `node --import ./import-map-sync-hooks.js main.js`
|
|
should print `some module!`.
|
|
|
|
## Source map v3 support
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v13.7.0
|
|
- v12.17.0
|
|
-->
|
|
|
|
> Stability: 1 - Experimental
|
|
|
|
Helpers for interacting with the source map cache. This cache is
|
|
populated when source map parsing is enabled and
|
|
[source map include directives][] are found in a modules' footer.
|
|
|
|
To enable source map parsing, Node.js must be run with the flag
|
|
[`--enable-source-maps`][], or with code coverage enabled by setting
|
|
[`NODE_V8_COVERAGE=dir`][].
|
|
|
|
```mjs
|
|
// module.mjs
|
|
// In an ECMAScript module
|
|
import { findSourceMap, SourceMap } from 'node:module';
|
|
```
|
|
|
|
```cjs
|
|
// module.cjs
|
|
// In a CommonJS module
|
|
const { findSourceMap, SourceMap } = require('node:module');
|
|
```
|
|
|
|
### `module.getSourceMapsSupport()`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.7.0
|
|
- v22.14.0
|
|
-->
|
|
|
|
* Returns: {Object}
|
|
* `enabled` {boolean} If the source maps support is enabled
|
|
* `nodeModules` {boolean} If the support is enabled for files in `node_modules`.
|
|
* `generatedCode` {boolean} If the support is enabled for generated code from `eval` or `new Function`.
|
|
|
|
This method returns whether the [Source Map v3][Source Map] support for stack
|
|
traces is enabled.
|
|
|
|
<!-- Anchors to make sure old links find a target -->
|
|
|
|
<a id="module_module_findsourcemap_path_error"></a>
|
|
|
|
### `module.findSourceMap(path)`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v13.7.0
|
|
- v12.17.0
|
|
-->
|
|
|
|
* `path` {string}
|
|
* Returns: {module.SourceMap|undefined} Returns `module.SourceMap` if a source
|
|
map is found, `undefined` otherwise.
|
|
|
|
`path` is the resolved path for the file for which a corresponding source map
|
|
should be fetched.
|
|
|
|
### `module.setSourceMapsSupport(enabled[, options])`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v23.7.0
|
|
- v22.14.0
|
|
-->
|
|
|
|
* `enabled` {boolean} Enable the source map support.
|
|
* `options` {Object} Optional
|
|
* `nodeModules` {boolean} If enabling the support for files in
|
|
`node_modules`. **Default:** `false`.
|
|
* `generatedCode` {boolean} If enabling the support for generated code from
|
|
`eval` or `new Function`. **Default:** `false`.
|
|
|
|
This function enables or disables the [Source Map v3][Source Map] support for
|
|
stack traces.
|
|
|
|
It provides same features as launching Node.js process with commandline options
|
|
`--enable-source-maps`, with additional options to alter the support for files
|
|
in `node_modules` or generated codes.
|
|
|
|
Only source maps in JavaScript files that are loaded after source maps has been
|
|
enabled will be parsed and loaded. Preferably, use the commandline options
|
|
`--enable-source-maps` to avoid losing track of source maps of modules loaded
|
|
before this API call.
|
|
|
|
### Class: `module.SourceMap`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v13.7.0
|
|
- v12.17.0
|
|
-->
|
|
|
|
#### `new SourceMap(payload[, { lineLengths }])`
|
|
|
|
<!-- YAML
|
|
changes:
|
|
- version: v20.5.0
|
|
pr-url: https://github.com/nodejs/node/pull/48461
|
|
description: Add support for `lineLengths`.
|
|
-->
|
|
|
|
* `payload` {Object}
|
|
* `lineLengths` {number\[]}
|
|
|
|
Creates a new `sourceMap` instance.
|
|
|
|
`payload` is an object with keys matching the [Source map v3 format][]:
|
|
|
|
* `file`: {string}
|
|
* `version`: {number}
|
|
* `sources`: {string\[]}
|
|
* `sourcesContent`: {string\[]}
|
|
* `names`: {string\[]}
|
|
* `mappings`: {string}
|
|
* `sourceRoot`: {string}
|
|
|
|
`lineLengths` is an optional array of the length of each line in the
|
|
generated code.
|
|
|
|
#### `sourceMap.payload`
|
|
|
|
* Returns: {Object}
|
|
|
|
Getter for the payload used to construct the [`SourceMap`][] instance.
|
|
|
|
#### `sourceMap.findEntry(lineOffset, columnOffset)`
|
|
|
|
* `lineOffset` {number} The zero-indexed line number offset in
|
|
the generated source
|
|
* `columnOffset` {number} The zero-indexed column number offset
|
|
in the generated source
|
|
* Returns: {Object}
|
|
|
|
Given a line offset and column offset in the generated source
|
|
file, returns an object representing the SourceMap range in the
|
|
original file if found, or an empty object if not.
|
|
|
|
The object returned contains the following keys:
|
|
|
|
* generatedLine: {number} The line offset of the start of the
|
|
range in the generated source
|
|
* generatedColumn: {number} The column offset of start of the
|
|
range in the generated source
|
|
* originalSource: {string} The file name of the original source,
|
|
as reported in the SourceMap
|
|
* originalLine: {number} The line offset of the start of the
|
|
range in the original source
|
|
* originalColumn: {number} The column offset of start of the
|
|
range in the original source
|
|
* name: {string}
|
|
|
|
The returned value represents the raw range as it appears in the
|
|
SourceMap, based on zero-indexed offsets, _not_ 1-indexed line and
|
|
column numbers as they appear in Error messages and CallSite
|
|
objects.
|
|
|
|
To get the corresponding 1-indexed line and column numbers from a
|
|
lineNumber and columnNumber as they are reported by Error stacks
|
|
and CallSite objects, use `sourceMap.findOrigin(lineNumber,
|
|
columnNumber)`
|
|
|
|
#### `sourceMap.findOrigin(lineNumber, columnNumber)`
|
|
|
|
<!-- YAML
|
|
added:
|
|
- v20.4.0
|
|
- v18.18.0
|
|
-->
|
|
|
|
* `lineNumber` {number} The 1-indexed line number of the call
|
|
site in the generated source
|
|
* `columnNumber` {number} The 1-indexed column number
|
|
of the call site in the generated source
|
|
* Returns: {Object}
|
|
|
|
Given a 1-indexed `lineNumber` and `columnNumber` from a call site in
|
|
the generated source, find the corresponding call site location
|
|
in the original source.
|
|
|
|
If the `lineNumber` and `columnNumber` provided are not found in any
|
|
source map, then an empty object is returned. Otherwise, the
|
|
returned object contains the following keys:
|
|
|
|
* name: {string | undefined} The name of the range in the
|
|
source map, if one was provided
|
|
* fileName: {string} The file name of the original source, as
|
|
reported in the SourceMap
|
|
* lineNumber: {number} The 1-indexed lineNumber of the
|
|
corresponding call site in the original source
|
|
* columnNumber: {number} The 1-indexed columnNumber of the
|
|
corresponding call site in the original source
|
|
|
|
[CommonJS]: modules.md
|
|
[Conditional exports]: packages.md#conditional-exports
|
|
[Customization hooks]: #customization-hooks
|
|
[ES Modules]: esm.md
|
|
[Permission Model]: permissions.md#permission-model
|
|
[Source Map]: https://sourcemaps.info/spec.html
|
|
[Source map v3 format]: https://sourcemaps.info/spec.html#h.mofvlxcwqzej
|
|
[V8 JavaScript code coverage]: https://v8project.blogspot.com/2017/12/javascript-code-coverage.html
|
|
[V8 code cache]: https://v8.dev/blog/code-caching-for-devs
|
|
[`"exports"`]: packages.md#exports
|
|
[`--enable-source-maps`]: cli.md#--enable-source-maps
|
|
[`--import`]: cli.md#--importmodule
|
|
[`--require`]: cli.md#-r---require-module
|
|
[`NODE_COMPILE_CACHE=dir`]: cli.md#node_compile_cachedir
|
|
[`NODE_DISABLE_COMPILE_CACHE=1`]: cli.md#node_disable_compile_cache1
|
|
[`NODE_V8_COVERAGE=dir`]: cli.md#node_v8_coveragedir
|
|
[`SourceMap`]: #class-modulesourcemap
|
|
[`initialize`]: #initialize
|
|
[`module.constants.compileCacheStatus`]: #moduleconstantscompilecachestatus
|
|
[`module.enableCompileCache()`]: #moduleenablecompilecachecachedir
|
|
[`module.flushCompileCache()`]: #moduleflushcompilecache
|
|
[`module.getCompileCacheDir()`]: #modulegetcompilecachedir
|
|
[`module`]: #the-module-object
|
|
[`os.tmpdir()`]: os.md#ostmpdir
|
|
[`registerHooks`]: #moduleregisterhooksoptions
|
|
[`register`]: #moduleregisterspecifier-parenturl-options
|
|
[`util.TextDecoder`]: util.md#class-utiltextdecoder
|
|
[chain]: #chaining
|
|
[hooks]: #customization-hooks
|
|
[load hook]: #loadurl-context-nextload
|
|
[module compile cache]: #module-compile-cache
|
|
[module wrapper]: modules.md#the-module-wrapper
|
|
[realm]: https://tc39.es/ecma262/#realm
|
|
[resolve hook]: #resolvespecifier-context-nextresolve
|
|
[source map include directives]: https://sourcemaps.info/spec.html#h.lmz475t4mvbx
|
|
[the documentation of `Worker`]: worker_threads.md#new-workerfilename-options
|
|
[transferable objects]: worker_threads.md#portpostmessagevalue-transferlist
|
|
[transform TypeScript features]: typescript.md#typescript-features
|
|
[type-stripping]: typescript.md#type-stripping
|