Node.js v21.7.2 ドキュメント
- Node.js v21.7.2
- ► 目次
-
► インデックス
- アサーションテスト
- 非同期コンテキストの追跡
- 非同期フック
- バッファ
- C++ アドオン
- Node-API を使用した C/C++ アドオン
- C++ エンベッダーAPI
- 子プロセス
- クラスタ
- コマンドラインオプション
- コンソール
- Corepack
- 暗号化
- デバッガ
- 非推奨API
- 診断チャネル
- DNS
- ドメイン
- エラー
- イベント
- ファイルシステム
- グローバルオブジェクト
- HTTP
- HTTP/2
- HTTPS
- インスペクタ
- 国際化
- モジュール: CommonJS モジュール
- モジュール: ECMAScript モジュール
- モジュール: `node:module` API
- モジュール: パッケージ
- ネットワーク
- OS
- パス
- パフォーマンスフック
- パーミッション
- プロセス
- Punnycode
- クエリ文字列
- Readline
- REPL
- レポート
- 単一実行可能アプリケーション
- ストリーム
- 文字列デコーダ
- テストランナー
- タイマー
- TLS/SSL
- トレースイベント
- TTY
- UDP/データグラム
- URL
- ユーティリティ
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- ワーカー スレッド
- Zlib
- ► その他のバージョン
- ► オプション
モジュール: `node:module` API#
`Module` オブジェクト#
`Module` のインスタンスを操作する際に一般的に使用されるユーティリティメソッドを提供します。これは、CommonJS モジュールでよく見られる `module` 変数です。`import 'node:module'` または `require('node:module')` を介してアクセスできます。
`module.builtinModules`#
Node.js によって提供されるすべてのモジュールの名前のリストです。サードパーティによって保守されているモジュールかどうかを確認するために使用できます。
このコンテキストでの `module` は、モジュールラッパーによって提供されるオブジェクトと同じではありません。アクセスするには、`Module` モジュールを require します。
// module.mjs
// In an ECMAScript module
import { builtinModules as builtin } from 'node:module';
// module.cjs
// In a CommonJS module
const builtin = require('node:module').builtinModules;
`module.createRequire(filename)`#
- `filename` <string> | <URL> require 関数の構築に使用されるファイル名。ファイルURLオブジェクト、ファイルURL文字列、または絶対パス文字列でなければなりません。
- 戻り値: <require> require 関数
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// sibling-module.js is a CommonJS module.
const siblingModule = require('./sibling-module');
`module.isBuiltin(moduleName)`#
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('wss'); // false
`module.register(specifier[, parentURL][, options])`#
- `specifier` <string> | <URL> 登録するカスタマイズフック。`import()` に渡される文字列と同じである必要がありますが、相対的な場合は `parentURL` を基準に解決されます。
- `parentURL` <string> | <URL> `specifier` を `import.meta.url` のようなベース URL を基準に解決する場合は、ここでその URL を渡すことができます。`parentURL` が2番目の引数として渡された場合、このプロパティは無視されます。**デフォルト:** `'data:'`
- `options` <Object>
- `parentURL` <string> | <URL> `specifier` を `import.meta.url` のようなベース URL を基準に解決する場合は、ここでその URL を渡すことができます。2番目の引数として `parentURL` が指定されている場合は、このプロパティは無視されます。**デフォルト:** `'data:'`
- `data` <any> `initialize` フックに渡す任意の複製可能な JavaScript の値。
- `transferList` <Object[]> 転送可能なオブジェクト を `initialize` フックに渡します。
Node.js のモジュール解決と読み込みの動作をカスタマイズするフックをエクスポートするモジュールを登録します。カスタマイズフックを参照してください。
`module.syncBuiltinESMExports()`#
`module.syncBuiltinESMExports()` メソッドは、ビルトイン ES モジュール のすべてのライブバインディングを CommonJS エクスポートのプロパティと一致するように更新します。ES モジュール からエクスポートされた名前を追加または削除することはありません。
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);
});
カスタマイズフック#
有効化#
モジュールの解決と読み込みは、フックのセットをエクスポートするファイルを登録することでカスタマイズできます。これは、`--import` フラグを使用してアプリケーションコードの前に実行できる `node:module` の `register` メソッドを使用して行うことができます。
node --import ./register-hooks.js ./my-app.js
// register-hooks.js
import { register } from 'node:module';
register('./hooks.mjs', import.meta.url);
// register-hooks.js
const { register } = require('node:module');
const { pathToFileURL } = require('node:url');
register('./hooks.mjs', pathToFileURL(__filename));
`--import` に渡されるファイルは、依存関係からのエクスポートでもかまいません。
node --import some-package/register ./my-app.js
ここで、`some-package` には ` "exports"` フィールドがあり、` /register` エクスポートを `register()` を呼び出すファイルにマッピングします。次の `register-hooks.js` の例のように。
`--import` を使用すると、アプリケーションファイル(アプリケーションのエントリポイントを含む)がインポートされる前にフックが登録されます。あるいは、エントリポイントから `register` を呼び出すこともできますが、フックが登録された後に実行されるコードには、動的な `import()` を使用する必要があります。
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');
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');
この例では、`http-to-https` フックを登録していますが、これはその後でインポートされたモジュール(この場合は `my-app.js` と、それが `import`(およびオプションで `require`)を介して参照するすべて)に対してのみ使用できます。`import('./my-app.js')` が静的な `import './my-app.js'` だった場合、アプリは `http-to-https` フックが登録される *前* に既にロードされています。これは、静的インポートが最初にツリーの葉から評価され、次に幹に戻る ES モジュール仕様によるものです。`my-app.js` 内には静的インポートがある可能性があり、これは `my-app.js` が動的にインポートされるまで評価されません。
`my-app.js` は CommonJS でもかまいません。カスタマイズフックは、それが `import`(およびオプションで `require`)を介して参照するすべてのモジュールに対して実行されます。
最後に、アプリの実行前にフックを登録するだけで、その目的で別のファイルを作成したくない場合は、`--import` に `data:` URL を渡すことができます。
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("http-to-https", pathToFileURL("./"));' ./my-app.js
チェーン化#
`register` を複数回呼び出すことができます。
// entrypoint.mjs
import { register } from 'node:module';
register('./foo.mjs', import.meta.url);
register('./bar.mjs', import.meta.url);
await import('./my-app.mjs');
// 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');
この例では、登録されたフックはチェーンを形成します。これらのチェーンは、後入れ先出し (LIFO) で実行されます。`foo.mjs` と `bar.mjs` の両方が `resolve` フックを定義している場合、次のように呼び出されます(右から左に注意してください)。Node.js のデフォルト ← `./foo.mjs` ← `./bar.mjs`(`./bar.mjs` から開始し、次に `./foo.mjs`、最後に Node.js のデフォルト)。これは他のすべてのフックにも当てはまります。
登録されたフックは `register` 自体にも影響します。この例では、`bar.mjs` は `foo.mjs` によって登録されたフックを介して解決およびロードされます(`foo` のフックは既にチェーンに追加されているため)。これにより、以前登録されたフックが JavaScript にトランスパイルされる限り、JavaScript 以外の言語でフックを作成することが可能になります。
`register` メソッドは、フックを定義するモジュール内からは呼び出すことができません。
モジュールカスタマイズフックとの通信#
モジュールカスタマイズフックは、アプリケーションコードを実行するメインスレッドとは別の専用スレッドで実行されます。つまり、グローバル変数を変更しても他のスレッドには影響せず、スレッド間で通信するにはメッセージチャネルを使用する必要があります。
`register` メソッドを使用して、`initialize` フックにデータを渡すことができます。フックに渡されるデータには、ポートなどの転送可能なオブジェクトを含めることができます。
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);
});
register('./my-hooks.mjs', {
parentURL: import.meta.url,
data: { number: 1, port: port2 },
transferList: [port2],
});
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);
});
register('./my-hooks.mjs', {
parentURL: pathToFileURL(__filename),
data: { number: 1, port: port2 },
transferList: [port2],
});
フック#
`register` メソッドを使用して、フックのセットをエクスポートするモジュールを登録できます。フックは、Node.js によって呼び出されてモジュールの解決と読み込みプロセスをカスタマイズする関数です。エクスポートされた関数は、特定の名前とシグネチャを持つ必要があり、名前付きエクスポートとしてエクスポートする必要があります。
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.
}
フックは チェーン の一部であり、そのチェーンがカスタム(ユーザー提供)フックと常に存在するデフォルトフックの1つだけから構成されている場合でもそうです。フック関数はネストされます。それぞれが常にプレーンオブジェクトを返す必要があり、チェーン化は各関数が `next<hookName>()` を呼び出すことによって行われます。これは、後続のローダーのフック(LIFO順)への参照です。
必須プロパティが欠落している値を返すフックは、例外をトリガーします。next<hookName>()
を呼び出さずに *かつ* shortCircuit: true
を返さないフックも、例外をトリガーします。これらのエラーは、チェーンの意図しない中断を防ぐためのものです。フックでチェーンが意図的に終了することを示すには、shortCircuit: true
を返してください。
フックは、アプリケーションコードが実行されるメインスレッドから分離された別スレッドで実行されます。つまり、異なるレルムです。フックスレッドは、メインスレッドによっていつでも終了される可能性があるため、非同期操作(console.log
など)の完了に依存しないでください。
initialize()
#
data
<任意>register(loader, import.meta.url, { data })
からのデータ。
initialize
フックは、フックモジュールが初期化されたときにフックスレッドで実行されるカスタム関数を定義する方法を提供します。初期化は、register
を介してフックモジュールが登録されたときに発生します。
このフックは、ポートやその他の転送可能なオブジェクトを含む、register
の呼び出しからデータを受信できます。initialize
の戻り値は<Promise>にすることができ、その場合、メインアプリケーションスレッドの実行が再開される前に待機されます。
モジュールカスタマイズコード
// path-to-my-hooks.js
export async function initialize({ number, port }) {
port.postMessage(`increment: ${number + 1}`);
}
呼び出し元コード
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');
});
register('./path-to-my-hooks.js', {
parentURL: import.meta.url,
data: { number: 1, port: port2 },
transferList: [port2],
});
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');
});
register('./path-to-my-hooks.js', {
parentURL: pathToFileURL(__filename),
data: { number: 1, port: port2 },
transferList: [port2],
});
resolve(specifier, context, nextResolve)
#
specifier
<文字列>context
<オブジェクト>nextResolve
<関数> チェーン内の次のresolve
フック、または最後のユーザー指定のresolve
フック後のNode.jsのデフォルトresolve
フック- 戻り値: <オブジェクト> | <Promise>
警告 Promiseと非同期関数の返却をサポートしていますが、
resolve
への呼び出しはメインスレッドをブロックする可能性があり、パフォーマンスに影響を与える可能性があります。
resolve
フックチェーンは、与えられたimport
文または式、またはrequire
呼び出しを見つける場所と、どのようにキャッシュするかをNode.jsに伝える役割を担っています。オプションで、フォーマット(例:'module'
)をload
フックへのヒントとして返すことができます。フォーマットが指定されている場合、最終的なformat
値を提供するのはload
フックの責任であり(resolve
から提供されたヒントを無視することもできます)、resolve
がformat
を提供する場合、Node.jsのデフォルトload
フックに値を渡すためだけでも、カスタムload
フックが必要です。
インポートタイプの属性は、読み込まれたモジュールを内部モジュールキャッシュに保存するためのキャッシュキーの一部です。モジュールをソースコードとは異なる属性でキャッシュする必要がある場合、resolve
フックはimportAttributes
オブジェクトを返す必要があります。
context
内のconditions
プロパティは、この解決要求に適用されるパッケージエクスポート条件の条件の配列です。これらは、他の場所で条件付きマッピングを検索したり、デフォルトの解決ロジックを呼び出す際にリストを変更するために使用できます。
現在のパッケージエクスポート条件は、常にフックに渡されるcontext.conditions
配列にあります。defaultResolve
を呼び出す際に、 *Node.jsモジュール指定子のデフォルトの解決動作* を保証するには、それに渡されるcontext.conditions
配列に、元のresolve
フックに渡されたcontext.conditions
配列の *すべての* 要素を含める *必要があります*。
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);
}
load(url, context, nextLoad)
#
url
<文字列>resolve
チェーンによって返されるURLcontext
<オブジェクト>nextLoad
<関数> チェーン内の次のload
フック、または最後のユーザー指定のload
フック後のNode.jsのデフォルトload
フック- 戻り値: <オブジェクト>
format
<文字列>shortCircuit
<未定義> | <ブール値> このフックがresolve
フックのチェーンを終了することを示すシグナル。デフォルト:false
source
<文字列> | <ArrayBuffer> | <TypedArray> Node.jsが評価するソース
load
フックは、URLの解釈、取得、解析方法を決定するカスタムメソッドを定義する方法を提供します。また、インポートアサーションの検証も担当します。
format
の最終値は次のいずれかである必要があります。
format | 説明 | load によって返されるsource の許容される型 |
---|---|---|
'builtin' | Node.js組み込みモジュールのロード | 適用外 |
'commonjs' | Node.js CommonJSモジュールのロード | { 文字列 、ArrayBuffer 、TypedArray 、null 、undefined } |
'json' | JSONファイルのロード | { 文字列 、ArrayBuffer 、TypedArray } |
'module' | ESモジュールのロード | { 文字列 、ArrayBuffer 、TypedArray } |
'wasm' | WebAssemblyモジュールのロード | { ArrayBuffer 、TypedArray } |
現在、Node.js組み込み(コア)モジュールの値を置き換えることができないため、型'builtin'
ではsource
の値は無視されます。
'commonjs'
のsource
を省略することと提供することには、非常に異なる効果があります。
source
が提供されると、このモジュールからのすべてのrequire
呼び出しは、登録されたresolve
およびload
フックを使用してESMローダーによって処理されます。このモジュールからのすべてのrequire.resolve
呼び出しは、登録されたresolve
フックを使用してESMローダーによって処理されます。CommonJS APIの一部分のみが使用可能になります(例:require.extensions
、require.cache
、require.resolve.paths
はありません)。また、CommonJSモジュールローダーに対するモンキーパッチングは適用されません。source
が未定義またはnull
の場合、CommonJSモジュールローダーによって処理され、require
/require.resolve
呼び出しは登録されたフックを通過しません。nullish
なsource
に対するこの動作は一時的なものです。将来、nullish
なsource
はサポートされなくなります。
node
が--experimental-default-type=commonjs
で実行されると、Node.js内部のload
実装(load
チェーンの最後のフックのnext
の値)は、後方互換性のためにformat
が'commonjs'
の場合、source
にnull
を返します。 こちらが、デフォルト以外の動作を使用するための例となるフックです。
import { readFile } from 'node:fs/promises';
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;
}
警告: ESM
load
フックとCommonJSモジュールからの名前空間付きエクスポートは互換性がありません。これらを一緒に使用しようとすると、インポートから空のオブジェクトが返されます。これは将来対処される可能性があります。
これらの型はすべて、ECMAScriptで定義されたクラスに対応しています。
- 具体的な
ArrayBuffer
オブジェクトはSharedArrayBuffer
です。 - 具体的な
TypedArray
オブジェクトはUint8Array
です。
テキストベースのフォーマット(つまり、'json'
、'module'
)のsource値が文字列でない場合、util.TextDecoder
を使用して文字列に変換されます。
load
フックは、解決済みのURLのソースコードを取得するためのカスタムメソッドを定義する方法を提供します。これにより、ローダーはディスクからのファイル読み取りを回避できる可能性があります。また、認識されないフォーマットをサポートされているフォーマットにマッピングするためにも使用できます(例:yaml
をmodule
に)。
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);
}
より高度なシナリオでは、サポートされていないソースをサポートされているソースに変換するためにも使用できます(下記の例を参照)。
例#
さまざまなモジュールカスタマイズフックを組み合わせて使用することで、Node.jsのコード読み込みと評価動作を幅広くカスタマイズできます。
HTTPSからのインポート#
現在のNode.jsでは、https://
で始まる指定子は実験的です(HTTPSとHTTPインポートを参照)。
以下のフックは、そのような指定子に対する基本的なサポートを有効にするフックを登録します。これはNode.jsコア機能への大きな改善のように見えるかもしれませんが、これらのフックを実際に使用することには大きな欠点があります。パフォーマンスはディスクからのファイル読み込みよりもはるかに遅く、キャッシングがなく、セキュリティもありません。
// 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);
}
// main.mjs
import { VERSION } from 'https://coffeescript.dokyumento.jp/browser-compiler-modern/coffeescript.js';
console.log(VERSION);
上記のフックモジュールを使用すると、node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs
を実行すると、main.mjs
のURLにあるモジュールに従って、CoffeeScriptの現在のバージョンが出力されます。
トランスパイル#
Node.jsが理解できない形式のソースは、load
フックを使用してJavaScriptに変換できます。
これは、Node.jsを実行する前にソースファイルをトランスパイルするよりもパフォーマンスが低くなります。トランスパイラフックは、開発とテストの目的でのみ使用する必要があります。
// coffeescript-hooks.mjs
import { readFile } from 'node:fs/promises';
import { dirname, extname, resolve as resolvePath } from 'node:path';
import { cwd } from 'node:process';
import { fileURLToPath, pathToFileURL } from 'node:url';
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, so we want any
// CoffeeScript file to be treated by Node.js the same as a .js file at the
// same location. To determine how Node.js would interpret an arbitrary .js
// file, search up the file system for the nearest parent package.json file
// and read its "type" field.
const format = await getPackageType(url);
const { source: rawSource } = await nextLoad(url, { ...context, format });
// This hook converts CoffeeScript source code into JavaScript source code
// for all imported CoffeeScript files.
const transformedSource = coffeescript.compile(rawSource.toString(), url);
return {
format,
shortCircuit: true,
source: transformedSource,
};
}
// Let Node.js handle all other URLs.
return nextLoad(url);
}
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 isFilePath = !!extname(url);
// If it is a file path, get the directory it's in
const dir = isFilePath ?
dirname(fileURLToPath(url)) :
url;
// Compose a file path to a package.json in the same directory,
// which may or may not exist
const packagePath = resolvePath(dir, 'package.json');
// Try to read the possibly nonexistent package.json
const type = await readFile(packagePath, { encoding: 'utf8' })
.then((filestring) => JSON.parse(filestring).type)
.catch((err) => {
if (err?.code !== 'ENOENT') console.error(err);
});
// If package.json existed and contained a `type` field with a value, voilà
if (type) return type;
// Otherwise, (if not at the root) continue checking the next directory up
// If at the root, stop and return false
return dir.length > 1 && getPackageType(resolvePath(dir, '..'));
}
# 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}"
# scream.coffee
export scream = (str) -> str.toUpperCase()
上記のフックモジュールを使用すると、node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./coffeescript-hooks.mjs"));' ./main.coffee
を実行すると、ディスクからソースコードが読み込まれた後、Node.jsが実行する前にmain.coffee
がJavaScriptに変換されます。そして、読み込まれたファイルのimport
ステートメントを介して参照されるすべての.coffee
、.litcoffee
、または.coffee.md
ファイルについても同様です。
インポートマップ#
前の2つの例ではload
フックを定義しました。これはresolve
フックの例です。このフックモジュールは、どの指定子を他のURLに上書きするかを定義するimport-map.json
ファイルを読み取ります(これは「インポートマップ」仕様の小さなサブセットの非常に単純な実装です)。
// 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);
}
これらのファイルを使用します。
// main.js
import 'a-module';
// import-map.json
{
"imports": {
"a-module": "./some-module.js"
}
}
// some-module.js
console.log('some module!');
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./import-map-hooks.js"));' main.js
を実行すると、some module!
が出力されます。
ソースマップv3サポート#
ソースマップキャッシュとの対話のためのヘルパー。このキャッシュは、ソースマップの解析が有効になっており、モジュールのフッターにソースマップインクルードディレクティブが見つかった場合に設定されます。
ソースマップの解析を有効にするには、Node.jsを--enable-source-maps
フラグ付きで実行するか、NODE_V8_COVERAGE=dir
を設定してコードカバレッジを有効にする必要があります。
// module.mjs
// In an ECMAScript module
import { findSourceMap, SourceMap } from 'node:module';
// module.cjs
// In a CommonJS module
const { findSourceMap, SourceMap } = require('node:module');
module.findSourceMap(path)
#
path
<string>- 戻り値: <module.SourceMap> | <undefined> ソースマップが見つかった場合は
module.SourceMap
を、そうでない場合はundefined
を返します。
path
は、対応するソースマップを取得する必要があるファイルの解決済みパスです。
クラス: module.SourceMap
#
new SourceMap(payload[, { lineLengths }])
#
payload
<Object>lineLengths
<number[]>
新しいsourceMap
インスタンスを作成します。
payload
は、ソースマップv3形式に一致するキーを持つオブジェクトです。
file
: <string>version
: <number>sources
: <string[]>sourcesContent
: <string[]>names
: <string[]>mappings
: <string>sourceRoot
: <string>
lineLengths
は、生成されたコードの各行の長さのオプションの配列です。
sourceMap.payload
#
- 戻り値: <オブジェクト>
SourceMap
インスタンスの構築に使用されたペイロードのゲッターです。
sourceMap.findEntry(lineOffset, columnOffset)
#
lineOffset
<number> 生成されたソースの0ベースの行番号オフセットcolumnOffset
<number> 生成されたソースの0ベースの列番号オフセット- 戻り値: <オブジェクト>
生成されたソースファイルの行オフセットと列オフセットを指定すると、見つかった場合は元のファイルのSourceMap範囲を表すオブジェクトを、見つからない場合は空のオブジェクトを返します。
返されるオブジェクトには、次のキーが含まれています。
- generatedLine: <number> 生成されたソースの範囲の先頭の行オフセット
- generatedColumn: <number> 生成されたソースの範囲の先頭の列オフセット
- originalSource: <string> SourceMapに報告されている元のソースのファイル名
- originalLine: <number> 元のソースの範囲の先頭の行オフセット
- originalColumn: <number> 元のソースの範囲の先頭の列オフセット
- name: <string>
返された値は、エラーメッセージとCallSiteオブジェクトに表示されるように、1ベースの行番号と列番号ではなく、0ベースのオフセットに基づいたSourceMapに表示される生の範囲を表します。
エラースタックとCallSiteオブジェクトによって報告されるlineNumberとcolumnNumberから対応する1ベースの行番号と列番号を取得するには、sourceMap.findOrigin(lineNumber, columnNumber)
を使用します。
sourceMap.findOrigin(lineNumber, columnNumber)
#
lineNumber
<number> 生成されたソースの呼び出しサイトの1ベースの行番号columnNumber
<number> 生成されたソースの呼び出しサイトの1ベースの列番号- 戻り値: <オブジェクト>
生成されたソースの呼び出しサイトの1ベースのlineNumber
とcolumnNumber
を指定して、元のソースの対応する呼び出しサイトの位置を見つけます。
提供されたlineNumber
とcolumnNumber
がソースマップに見つからない場合、空のオブジェクトが返されます。それ以外の場合、返されるオブジェクトには次のキーが含まれます。
- name: <string> | <undefined> 提供された場合、ソースマップ内の範囲の名前
- fileName: <string> SourceMapに報告されている元のソースのファイル名
- lineNumber: <number> 元のソースの対応する呼び出しサイトの1ベースのlineNumber
- columnNumber: <number> 元のソースの対応する呼び出しサイトの1ベースのcolumnNumber