モジュール: ECMAScript モジュール#

安定性: 2 - Stable

はじめに#

ECMAScript モジュールは、再利用のために JavaScript コードをパッケージ化するための公式の標準フォーマットです。モジュールは、さまざまな import 文と export 文を使用して定義されます。

次の ES モジュールの例は、関数をエクスポートします

// addTwo.mjs
function addTwo(num) {
  return num + 2;
}

export { addTwo }; 

次の ES モジュールの例は、addTwo.mjs から関数をインポートします

// app.mjs
import { addTwo } from './addTwo.mjs';

// Prints: 6
console.log(addTwo(4)); 

Node.js は、現在指定されている ECMAScript モジュールを完全にサポートしており、それらと元のモジュール形式である CommonJS との間の相互運用性を提供します。

有効化#

Node.js には、CommonJS モジュールと ECMAScript モジュールの 2 つのモジュールシステムがあります。

開発者は、.mjs ファイル拡張子、package.json"type" フィールドに値 "module" を設定、または --input-type フラグに値 "module" を設定することで、JavaScript を ES モジュールとして解釈するよう Node.js に指示できます。これらは、コードが ES モジュールとして実行されることを意図している明示的なマーカーです。

逆に、開発者は、.cjs ファイル拡張子、package.json"type" フィールドに値 "commonjs" を設定、または --input-type フラグに値 "commonjs" を設定することで、JavaScript を CommonJS として解釈するよう Node.js に明示的に指示できます。

どちらのモジュールシステムにも明示的なマーカーがないコードの場合、Node.js はモジュールのソースコードを検査して ES モジュールの構文を探します。そのような構文が見つかった場合、Node.js はコードを ES モジュールとして実行します。それ以外の場合は、モジュールを CommonJS として実行します。詳細については、モジュールシステムの決定を参照してください。

パッケージ#

このセクションは モジュール: パッケージ に移動しました。

import 指定子#

用語#

import 文の*指定子*は、from キーワードの後の文字列です。例: import { sep } from 'node:path''node:path'。指定子は、export from 文や、import() 式の引数としても使用されます。

指定子には 3 つの種類があります

  • 相対指定子: './startup.js''../config.mjs' など。これらは、インポート元のファイルの場所からの相対パスを参照します。これらにはファイル拡張子が常に必要です。

  • ベア指定子: 'some-package''some-package/shuffle' など。これらは、パッケージ名によるパッケージのメインエントリポイント、または例のようにパッケージ名が接頭辞として付いたパッケージ内の特定の機能モジュールを参照できます。ファイル拡張子を含める必要があるのは、"exports" フィールドを持たないパッケージのみです。

  • 絶対指定子: 'file:///opt/nodejs/config.js' など。これらは、完全なパスを直接かつ明示的に参照します。

ベア指定子の解決は、Node.js モジュール解決および読み込みアルゴリズムによって処理されます。他のすべての指定子の解決は、常に標準的な相対 URL 解決セマンティクスによってのみ解決されます。

CommonJS と同様に、パッケージ内のモジュールファイルには、パッケージ名にパスを追加することでアクセスできます。ただし、パッケージの package.json"exports" フィールドが含まれている場合を除きます。その場合、パッケージ内のファイルは "exports" で定義されたパスを介してのみアクセスできます。

Node.js モジュール解決におけるベア指定子に適用されるこれらのパッケージ解決ルールに関する詳細は、パッケージのドキュメンテーションを参照してください。

必須のファイル拡張子#

相対または絶対指定子を解決するために import キーワードを使用する場合、ファイル拡張子を提供する必要があります。ディレクトリインデックス (例: './startup/index.js') も完全に指定する必要があります。

この動作は、通常設定されたサーバーを想定した場合の、ブラウザ環境での import の動作と一致します。

URL#

ES モジュールは URL として解決され、キャッシュされます。これは、#%23 に、?%3F にするなど、特殊文字をパーセントエンコードする必要があることを意味します。

file:node:、および data: URL スキームがサポートされています。'https://example.com/app.js' のような指定子は、カスタム HTTPS ローダーを使用しない限り、Node.js でネイティブにはサポートされていません。

file: URL#

モジュールを解決するために使用される import 指定子が異なるクエリまたはフラグメントを持つ場合、モジュールは複数回読み込まれます。

import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2" 

ボリュームルートは ///、または file:/// を介して参照できます。URL とパスの解決の違い (パーセントエンコーディングの詳細など) を考慮すると、パスをインポートする際には url.pathToFileURL を使用することが推奨されます。

data: インポート#

data: URL は、以下の MIME タイプでのインポートがサポートされています

  • ES モジュール用の text/javascript
  • JSON 用の application/json
  • Wasm 用の application/wasm
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' with { type: 'json' }; 

data: URL は、組み込みモジュールのベア指定子絶対指定子のみを解決します。data:特別なスキームではないため、相対指定子の解決は機能しません。例えば、data:text/javascript,import "./foo"; から ./foo をロードしようとすると、data: URL には相対解決の概念がないため、解決に失敗します。

node: インポート#

node: URL は、Node.js の組み込みモジュールをロードする代替手段としてサポートされています。この URL スキームにより、組み込みモジュールを有効な絶対 URL 文字列で参照できます。

import fs from 'node:fs/promises'; 

インポート属性#

インポート属性は、モジュール指定子とともに追加情報を渡すための、モジュールインポート文のインライン構文です。

import fooData from './foo.json' with { type: 'json' };

const { default: barData } =
  await import('./bar.json', { with: { type: 'json' } }); 

Node.js は type 属性のみをサポートしており、以下の値をサポートしています

属性 type必要な場合
'json'JSON モジュール

JSON モジュールをインポートする際には type: 'json' 属性が必須です。

組み込みモジュール#

組み込みモジュールは、その公開 API の名前付きエクスポートを提供します。CommonJS の exports の値であるデフォルトエクスポートも提供されます。デフォルトエクスポートは、とりわけ名前付きエクスポートを変更するために使用できます。組み込みモジュールの名前付きエクスポートは、module.syncBuiltinESMExports() を呼び出すことによってのみ更新されます。

import EventEmitter from 'node:events';
const e = new EventEmitter(); 
import { readFile } from 'node:fs';
readFile('./foo.txt', (err, source) => {
  if (err) {
    console.error(err);
  } else {
    console.log(source);
  }
}); 
import fs, { readFileSync } from 'node:fs';
import { syncBuiltinESMExports } from 'node:module';
import { Buffer } from 'node:buffer';

fs.readFileSync = () => Buffer.from('Hello, ESM');
syncBuiltinESMExports();

fs.readFileSync === readFileSync; 

import()#

動的 import() は、モジュールを非同期にインポートする方法を提供します。これは CommonJS と ES モジュールの両方でサポートされており、CommonJS と ES モジュールの両方をロードするために使用できます。

import.meta#

import.meta メタプロパティは、以下のプロパティを含む Object です。これは ES モジュールでのみサポートされています。

import.meta.dirname#

  • 型: <string> 現在のモジュールのディレクトリ名。

これは import.meta.filenamepath.dirname() と同じです。

注意: file: モジュールにのみ存在します。

import.meta.filename#

  • 型: <string> シンボリックリンクが解決された、現在のモジュールの完全な絶対パスとファイル名。

これは import.meta.urlurl.fileURLToPath() と同じです。

注意: ローカルモジュールのみがこのプロパティをサポートします。file: プロトコルを使用しないモジュールはこれを提供しません。

import.meta.url#

  • 型: <string> モジュールの絶対的な file: URL。

これは、現在のモジュールファイルの URL を提供するブラウザと全く同じように定義されています。

これにより、相対ファイルの読み込みなどの便利なパターンが可能になります

import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url)); 

import.meta.main#

安定性: 1.0 - Early development

  • 型: <boolean> 現在のモジュールが現在のプロセスのエントリーポイントである場合は true、それ以外の場合は false

CommonJS の require.main === module と同等です。

Python の __name__ == "__main__" に類似しています。

export function foo() {
  return 'Hello, world';
}

function main() {
  const message = foo();
  console.log(message);
}

if (import.meta.main) main();
// `foo` can be imported from another module without possible side-effects from `main` 

import.meta.resolve(specifier)#

安定性: 1.2 - Release candidate

  • specifier <string> 現在のモジュールを基準に解決するモジュール指定子。
  • 戻り値: <string> 指定子が解決される絶対 URL 文字列。

import.meta.resolve は、各モジュールにスコープされたモジュール相対の解決関数であり、URL 文字列を返します。

const dependencyAsset = import.meta.resolve('component-lib/asset.css');
// file:///app/node_modules/component-lib/asset.css
import.meta.resolve('./dep.js');
// file:///app/dep.js 

Node.js モジュール解決のすべての機能がサポートされています。依存関係の解決は、パッケージ内で許可されているエクスポート解決に従います。

注意点:

  • これにより同期的なファイルシステム操作が発生する可能性があり、require.resolve と同様にパフォーマンスに影響を与える可能性があります。
  • この機能はカスタムローダー内では利用できません (デッドロックが発生するため)。

非標準 API:

--experimental-import-meta-resolve フラグを使用する場合、この関数は 2 番目の引数を受け入れます

  • parent <string> | <URL> 解決の基準となるオプションの絶対親モジュール URL。デフォルト: import.meta.url

CommonJS との相互運用性#

import#

import 文は、ES モジュールまたは CommonJS モジュールを参照できます。import 文は ES モジュールでのみ許可されていますが、動的な import() 式は CommonJS で ES モジュールをロードするためにサポートされています。

CommonJS モジュールをインポートする場合、module.exports オブジェクトがデフォルトエクスポートとして提供されます。名前付きエクスポートは、より良いエコシステム互換性のための便宜として静的解析によって提供される場合があります。

require#

CommonJS モジュールの require は現在、同期的な ES モジュール (つまり、トップレベルの await を使用しない ES モジュール) の読み込みのみをサポートしています。

詳細については、require() を使用した ECMAScript モジュールの読み込みを参照してください。

CommonJS 名前空間#

CommonJS モジュールは、任意の型の module.exports オブジェクトで構成されます。

これをサポートするため、ECMAScript モジュールから CommonJS をインポートする際には、CommonJS モジュールの名前空間ラッパーが構築されます。このラッパーは、常に CommonJS の module.exports 値を指す default エクスポートキーを提供します。

さらに、CommonJS モジュールのソーステキストに対してヒューリスティックな静的解析が実行され、module.exports の値から名前空間に提供するエクスポートの静的なリストをベストエフォートで取得します。これらの名前空間は CJS モジュールの評価前に構築する必要があるため、これが必要です。

これらの CommonJS 名前空間オブジェクトは、default エクスポートを 'module.exports' という名前付きエクスポートとしても提供します。これは、CommonJS での表現がこの値を使用し、名前空間の値ではないことを明確に示すためです。これは、require(esm) 相互運用サポートにおける 'module.exports' エクスポート名の処理セマンティクスを反映しています。

CommonJS モジュールをインポートする場合、ES モジュールのデフォルトインポートまたはそれに対応するシンタックスシュガーを使用して確実にインポートできます。

import { default as cjs } from 'cjs';
// Identical to the above
import cjsSugar from 'cjs';

console.log(cjs);
console.log(cjs === cjsSugar);
// Prints:
//   <module.exports>
//   true 

このモジュール名前空間エキゾチックオブジェクトは、import * as m from 'cjs' または動的インポートを使用するときに直接観察できます。

import * as m from 'cjs';
console.log(m);
console.log(m === await import('cjs'));
// Prints:
//   [Module] { default: <module.exports>, 'module.exports': <module.exports> }
//   true 

JS エコシステムでの既存の使用法との互換性を高めるため、Node.js はさらに、静的解析プロセスを使用して、インポートされたすべての CommonJS モジュールの CommonJS 名前付きエクスポートを決定し、それらを個別の ES モジュールエクスポートとして提供しようと試みます。

例えば、次のように書かれた CommonJS モジュールを考えてみましょう。

// cjs.cjs
exports.name = 'exported'; 

前述のモジュールは、ES モジュールでの名前付きインポートをサポートします。

import { name } from './cjs.cjs';
console.log(name);
// Prints: 'exported'

import cjs from './cjs.cjs';
console.log(cjs);
// Prints: { name: 'exported' }

import * as m from './cjs.cjs';
console.log(m);
// Prints:
//   [Module] {
//     default: { name: 'exported' },
//     'module.exports': { name: 'exported' },
//     name: 'exported'
//   } 

モジュール名前空間エキゾチックオブジェクトがログに記録された最後の例からわかるように、モジュールがインポートされると、name エクスポートは module.exports オブジェクトからコピーされ、ES モジュール名前空間に直接設定されます。

module.exports に追加されたライブバインディングの更新や新しいエクスポートは、これらの名前付きエクスポートでは検出されません。

名前付きエクスポートの検出は、一般的な構文パターンに基づいていますが、常に正しく名前付きエクスポートを検出するとは限りません。このような場合、上記で説明したデフォルトインポート形式を使用する方が良い選択肢となる場合があります。

名前付きエクスポートの検出は、多くの一般的なエクスポートパターン、再エクスポートパターン、ビルドツールやトランスパイラからの出力をカバーしています。実装されている正確なセマンティクスについては、cjs-module-lexer を参照してください。

ES モジュールと CommonJS の違い#

requireexportsmodule.exports がない#

ほとんどの場合、ES モジュールの import を使用して CommonJS モジュールを読み込むことができます。

必要であれば、module.createRequire() を使用して ES モジュール内に require 関数を構築できます。

__filename__dirname がない#

これらの CommonJS 変数は ES モジュールでは利用できません。

__filename__dirname のユースケースは、import.meta.filenameimport.meta.dirname を介して再現できます。

アドオンの読み込みがない#

アドオンは現在 ES モジュールインポートではサポートされていません。

代わりに module.createRequire() または process.dlopen を使用して読み込むことができます。

require.main がない#

require.main === module を置き換えるために、import.meta.main API があります。

require.resolve がない#

相対解決は new URL('./local', import.meta.url) を介して処理できます。

完全な require.resolve の代替として、import.meta.resolve API があります。

あるいは、module.createRequire() を使用することもできます。

NODE_PATH がない#

NODE_PATHimport 指定子の解決には関与しません。この動作が必要な場合は、シンボリックリンクを使用してください。

require.extensions がない#

require.extensionsimport では使用されません。モジュールカスタマイズフックが代替を提供できます。

require.cache がない#

ES モジュールローダーには独自のキャッシュがあるため、require.cacheimport では使用されません。

JSON モジュール#

JSON ファイルは import で参照できます

import packageConfig from './package.json' with { type: 'json' }; 

with { type: 'json' } 構文は必須です。インポート属性を参照してください。

インポートされた JSON は default エクスポートのみを公開します。名前付きエクスポートのサポートはありません。重複を避けるために CommonJS キャッシュにキャッシュエントリが作成されます。JSON モジュールが同じパスからすでにインポートされている場合、CommonJS でも同じオブジェクトが返されます。

Wasm モジュール#

WebAssembly モジュールインスタンスと WebAssembly ソースフェーズインポートの両方のインポートがサポートされています。

これらの統合はどちらも、WebAssembly の ES モジュール統合提案に沿っています。

Wasm ソースフェーズインポート#

安定性: 1.2 - Release candidate

ソースフェーズインポート提案により、import source キーワードの組み合わせで、依存関係がすでにインスタンス化されたモジュールインスタンスを取得する代わりに、WebAssembly.Module オブジェクトを直接インポートできます。

これは、Wasm を ES モジュール統合を通じて解決・読み込みしつつ、Wasm のカスタムインスタンス化が必要な場合に便利です。

たとえば、モジュールの複数のインスタンスを作成したり、library.wasm の新しいインスタンスにカスタムインポートを渡したりする場合などです

import source libraryModule from './library.wasm';

const instance1 = await WebAssembly.instantiate(libraryModule, importObject1);

const instance2 = await WebAssembly.instantiate(libraryModule, importObject2); 

静的ソースフェーズに加えて、import.source 動的フェーズインポート構文を介したソースフェーズの動的バリアントもあります

const dynamicLibrary = await import.source('./library.wasm');

const instance = await WebAssembly.instantiate(dynamicLibrary, importObject); 

JavaScript 文字列組み込み#

安定性: 1.2 - Release candidate

WebAssembly モジュールをインポートする際、WebAssembly JS 文字列組み込み提案は ESM 統合を通じて自動的に有効になります。これにより、WebAssembly モジュールは wasm:js-string 名前空間から効率的なコンパイル時文字列組み込みを直接使用できます。

例えば、以下の Wasm モジュールは wasm:js-stringlength 組み込みを使用して文字列 getLength 関数をエクスポートします

(module
  ;; Compile-time import of the string length builtin.
  (import "wasm:js-string" "length" (func $string_length (param externref) (result i32)))

  ;; Define getLength, taking a JS value parameter assumed to be a string,
  ;; calling string length on it and returning the result.
  (func $getLength (param $str externref) (result i32)
    local.get $str
    call $string_length
  )

  ;; Export the getLength function.
  (export "getLength" (func $get_length))
) 
import { getLength } from './string-len.wasm';
getLength('foo'); // Returns 3. 

Wasm 組み込みは、インスタンス化時ではなくモジュールコンパイル時にリンクされるコンパイル時インポートです。これらは通常のモジュールグラフインポートのように動作せず、WebAssembly.Module.imports(mod) を介して検査したり、文字列組み込みを無効にして直接 WebAssembly.compile API を使用してモジュールを再コンパイルしない限り仮想化したりすることはできません。

インスタンス化される前にソースフェーズでモジュールをインポートする場合も、コンパイル時の組み込みが自動的に使用されます

import source mod from './string-len.wasm';
const { exports: { getLength } } = await WebAssembly.instantiate(mod, {});
getLength('foo'); // Also returns 3. 

Wasm インスタンスフェーズインポート#

安定性: 1.1 - Active development

インスタンスインポートにより、任意の .wasm ファイルを通常のモジュールとしてインポートでき、そのモジュールインポートもサポートされます。

たとえば、以下を含む index.js

import * as M from './library.wasm';
console.log(M); 

以下のように実行された場合

node index.mjs 

library.wasm のインスタンス化のためのエクスポートインターフェースが提供されます。

予約済みの Wasm 名前空間#

WebAssembly モジュールインスタンスをインポートする場合、予約済みの接頭辞で始まるインポートモジュール名やインポート/エクスポート名は使用できません

  • wasm-js: - すべてのモジュールインポート名、モジュール名、エクスポート名で予約されています。
  • wasm: - モジュールインポート名とエクスポート名で予約されています (将来の組み込みポリフィルをサポートするため、インポートされたモジュール名は許可されています)。

上記の予約名を使用してモジュールをインポートすると、WebAssembly.LinkError がスローされます。

トップレベル await#

await キーワードは、ECMAScript モジュールのトップレベルの本体で使用できます。

以下のような a.mjs を想定します

export const five = await Promise.resolve(5); 

そして、以下のような b.mjs を想定します

import { five } from './a.mjs';

console.log(five); // Logs `5` 
node b.mjs # works 

トップレベルの await 式が解決されない場合、node プロセスは 13ステータスコードで終了します。

import { spawn } from 'node:child_process';
import { execPath } from 'node:process';

spawn(execPath, [
  '--input-type=module',
  '--eval',
  // Never-resolving Promise:
  'await new Promise(() => {})',
]).once('exit', (code) => {
  console.log(code); // Logs `13`
}); 

ローダー#

以前のローダーのドキュメントは、モジュール: カスタマイズフックにあります。

解決および読み込みアルゴリズム#

機能#

デフォルトのリゾルバには次のプロパティがあります

  • ES モジュールで使用される FileURL ベースの解決
  • 相対および絶対 URL 解決
  • デフォルトの拡張子なし
  • フォルダのメインなし
  • node_modules を通じたベア指定子パッケージ解決の検索
  • 未知の拡張子やプロトコルで失敗しない
  • 読み込みフェーズにフォーマットのヒントを任意で提供できる

デフォルトのローダーには次のプロパティがあります

  • node: URL を介した組み込みモジュール読み込みのサポート
  • data: URL を介した「インライン」モジュール読み込みのサポート
  • file: モジュール読み込みのサポート
  • 他の URL プロトコルでは失敗する
  • file: 読み込みで未知の拡張子の場合に失敗する (.cjs, .js, .mjs のみサポート)

解決アルゴリズム#

ES モジュール指定子を読み込むアルゴリズムは、以下の ESM_RESOLVE メソッドで与えられます。これは parentURL に相対的なモジュール指定子の解決済み URL を返します。

解決アルゴリズムは、モジュール読み込みのための完全に解決された URL を、推奨されるモジュールフォーマットとともに決定します。解決アルゴリズムは、解決された URL プロトコルが読み込み可能か、またはファイル拡張子が許可されているかを決定しません。代わりに、これらの検証は読み込みフェーズ中に Node.js によって適用されます (例えば、file:data:、または node: 以外のプロトコルを持つ URL の読み込みを要求された場合)。

アルゴリズムはまた、拡張子に基づいてファイルのフォーマットを決定しようとします (以下の ESM_FILE_FORMAT アルゴリズムを参照)。ファイル拡張子を認識しない場合 (例えば、.mjs.cjs、または .json でない場合)、undefined のフォーマットが返され、これは読み込みフェーズでエラーをスローします。

解決された URL のモジュールフォーマットを決定するアルゴリズムは ESM_FILE_FORMAT によって提供され、これは任意のファイルに対して一意のモジュールフォーマットを返します。ECMAScript モジュールには "module" フォーマットが返され、レガシーな CommonJS ローダーを介した読み込みを示すためには "commonjs" フォーマットが使用されます。"addon" などの追加フォーマットは将来の更新で拡張される可能性があります。

以下のアルゴリズムでは、特に明記されていない限り、すべてのサブルーチンのエラーはこれらのトップレベルルーチンのエラーとして伝播します。

defaultConditions は、条件付き環境名の配列 ["node", "import"] です。

リゾルバは以下のエラーをスローする可能性があります

  • Invalid Module Specifier: モジュール指定子が、無効な URL、パッケージ名、またはパッケージサブパス指定子です。
  • Invalid Package Configuration: package.json の設定が無効か、無効な設定を含んでいます。
  • Invalid Package Target: パッケージのエクスポートまたはインポートが、無効な型または文字列ターゲットであるパッケージのターゲットモジュールを定義しています。
  • Package Path Not Exported: パッケージのエクスポートが、与えられたモジュールのためのパッケージ内のターゲットサブパスを定義または許可していません。
  • Package Import Not Defined: パッケージのインポートが指定子を定義していません。
  • Module Not Found: 要求されたパッケージまたはモジュールが存在しません。
  • Unsupported Directory Import: 解決されたパスがディレクトリに対応しており、モジュールインポートのサポートされているターゲットではありません。

解決アルゴリズムの仕様#

ESM_RESOLVE(specifier, parentURL)

  1. resolvedundefined とする。
  2. specifier が有効な URL の場合、
    1. resolved に、specifier を URL としてパースし再シリアライズした結果をセットする。
  3. そうでなく、specifier"/", "./", または "../" で始まる場合、
    1. resolved に、parentURL を基準とした specifier の URL 解決の結果をセットする。
  4. そうでなく、specifier"#" で始まる場合、
    1. resolved に、PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions) の結果をセットする。
  5. それ以外の場合、
    1. 注意: specifier はベア指定子である。
    2. resolved に、PACKAGE_RESOLVE(specifier, parentURL) の結果をセットする。
  6. formatundefined とする。
  7. resolved"file:" URL の場合、
    1. resolved"/" または "\" のパーセントエンコーディング (それぞれ "%2F""%5C") を含む場合、
      1. Invalid Module Specifier エラーをスローする。
    2. resolved のファイルがディレクトリの場合、
      1. Unsupported Directory Import エラーをスローする。
    3. resolved のファイルが存在しない場合、
      1. Module Not Found エラーをスローする。
    4. resolved を、同じ URL クエリ文字列とフラグメントコンポーネントを維持しながら、resolved の実際のパスにセットする。
    5. format に、ESM_FILE_FORMAT(resolved) の結果をセットする。
  8. それ以外の場合、
    1. format に、URL resolved に関連付けられたコンテンツタイプのモジュールフォーマットをセットする。
  9. formatresolved を読み込みフェーズに返す。

PACKAGE_RESOLVE(packageSpecifier, parentURL)

  1. packageNameundefined とする。
  2. packageSpecifier が空の文字列の場合、
    1. Invalid Module Specifier エラーをスローする。
  3. packageSpecifier が Node.js の組み込みモジュール名の場合、
    1. 文字列 "node:"packageSpecifier を連結したものを返す。
  4. packageSpecifier"@" で始まらない場合、
    1. packageName を、packageSpecifier の最初の "/" 区切り文字まで、または文字列の終わりまでの部分文字列に設定する。
  5. それ以外の場合、
    1. packageSpecifier"/" 区切り文字を含まない場合、
      1. Invalid Module Specifier エラーをスローする。
    2. packageName を、packageSpecifier の 2 番目の "/" 区切り文字まで、または文字列の終わりまでの部分文字列に設定する。
  6. packageName"." で始まるか、"\" または "%" を含む場合、
    1. Invalid Module Specifier エラーをスローする。
  7. packageSubpath を、"."packageSpecifierpackageName の長さの位置からの部分文字列を連結したものとする。
  8. selfUrlPACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL) の結果とする。
  9. selfUrlundefined でない場合、selfUrl を返す。
  10. parentURL がファイルシステムのルートでない間、
    1. packageURL を、parentURL を基準とした "node_modules/"packageName を連結したものの URL 解決結果とする。
    2. parentURLparentURL の親フォルダ URL に設定する。
    3. packageURL のフォルダが存在しない場合、
      1. 次のループイテレーションを続ける。
    4. pjsonREAD_PACKAGE_JSON(packageURL) の結果とする。
    5. pjsonnull でなく、かつ pjson.exportsnull または undefined でない場合、
      1. PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) の結果を返す。
    6. そうでなく、packageSubpath"." と等しい場合、
      1. pjson.main が文字列の場合、
        1. packageURL 内の main の URL 解決結果を返す。
    7. それ以外の場合、
      1. packageURL 内の packageSubpath の URL 解決結果を返す。
  11. Module Not Found エラーをスローする。

PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)

  1. packageURLLOOKUP_PACKAGE_SCOPE(parentURL) の結果とする。
  2. packageURLnull の場合、
    1. undefined を返す。
  3. pjsonREAD_PACKAGE_JSON(packageURL) の結果とする。
  4. pjsonnull の場合、または pjson.exportsnull または undefined の場合、
    1. undefined を返す。
  5. pjson.namepackageName と等しい場合、
    1. PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) の結果を返す。
  6. それ以外の場合は undefined を返す。

PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)

注意: この関数は CommonJS 解決アルゴリズムによって直接呼び出されます。

  1. exports"." で始まるキーと "." で始まらないキーの両方を持つオブジェクトの場合、Invalid Package Configuration エラーをスローする。
  2. subpath"." と等しい場合、
    1. mainExportundefined とする。
    2. exports が文字列、配列、または "." で始まるキーを含まないオブジェクトの場合、
      1. mainExportexports に設定する。
    3. そうでなく、exports"." プロパティを含むオブジェクトの場合、
      1. mainExportexports["."] に設定する。
    4. mainExportundefined でない場合、
      1. resolvedPACKAGE_TARGET_RESOLVE( packageURL, mainExport, null, false, conditions) の結果とする。
      2. resolvednull または undefined でない場合、resolved を返す。
  3. そうでなく、exports がオブジェクトであり、exports のすべてのキーが "." で始まる場合、
    1. 表明: subpath"./" で始まる。
    2. resolvedPACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions) の結果とする。
    3. resolvednull または undefined でない場合、resolved を返す。
  4. Package Path Not Exported エラーをスローする。

PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)

注意: この関数は CommonJS 解決アルゴリズムによって直接呼び出されます。

  1. 表明: specifier"#" で始まる。
  2. specifier が厳密に "#" と等しいか、"#/" で始まる場合、
    1. Invalid Module Specifier エラーをスローする。
  3. packageURLLOOKUP_PACKAGE_SCOPE(parentURL) の結果とする。
  4. packageURLnull でない場合、
    1. pjsonREAD_PACKAGE_JSON(packageURL) の結果とする。
    2. pjson.imports が null でないオブジェクトの場合、
      1. resolvedPACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) の結果とする。
      2. resolvednull または undefined でない場合、resolved を返す。
  5. Package Import Not Defined エラーをスローする。

PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)

  1. matchKey"/" で終わる場合、
    1. Invalid Module Specifier エラーをスローする。
  2. matchKeymatchObj のキーであり、"*" を含まない場合、
    1. targetmatchObj[matchKey] の値とする。
    2. PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions) の結果を返す。
  3. expansionKeys を、単一の "*" のみを含む matchObj のキーのリストとし、特定性の降順でソートするソート関数 PATTERN_KEY_COMPARE でソートする。
  4. expansionKeys の各キー expansionKey について、以下を実行する
    1. patternBase を、expansionKey の最初の "*" 文字までの部分文字列とする。
    2. matchKeypatternBase で始まるが等しくない場合、
      1. patternTrailer を、expansionKey の最初の "*" 文字の後のインデックスからの部分文字列とする。
      2. patternTrailer の長さがゼロであるか、matchKeypatternTrailer で終わり、かつ matchKey の長さが expansionKey の長さ以上である場合、
        1. targetmatchObj[expansionKey] の値とする。
        2. patternMatch を、matchKeypatternBase の長さのインデックスから始まり、matchKey の長さから patternTrailer の長さを引いた長さまでの部分文字列とする。
        3. PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions) の結果を返す。
  5. null を返す。

PATTERN_KEY_COMPARE(keyA, keyB)

  1. 表明: keyA は単一の "*" のみを含む。
  2. 表明: keyB は単一の "*" のみを含む。
  3. baseLengthAkeyA の中の "*" のインデックスとする。
  4. baseLengthBkeyB の中の "*" のインデックスとする。
  5. baseLengthAbaseLengthB より大きい場合、-1 を返す。
  6. baseLengthBbaseLengthA より大きい場合、1 を返す。
  7. keyA の長さが keyB の長さより大きい場合、-1 を返す。
  8. keyB の長さが keyA の長さより大きい場合、1 を返す。
  9. 0 を返す。

PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)

  1. target が文字列の場合、
    1. target"./" で始まらない場合、
      1. isImportsfalse の場合、または target"../" または "/" で始まる場合、または target が有効な URL の場合、
        1. Invalid Package Target エラーをスローする。
      2. patternMatch が文字列の場合、
        1. PACKAGE_RESOLVE(target のすべての "*"patternMatch で置き換えたもの, packageURL + "/") を返す。
      3. PACKAGE_RESOLVE(target, packageURL + "/") を返す。
    2. target"/" または "\" で分割したものが、最初の "." セグメントの後に """."".."、または "node_modules" セグメントを、大文字小文字を区別せず、パーセントエンコードされたバリアントを含めて含む場合、Invalid Package Target エラーをスローする。
    3. resolvedTargetpackageURLtarget を連結したものの URL 解決結果とする。
    4. 表明: packageURLresolvedTarget に含まれる。
    5. patternMatchnull の場合、
      1. resolvedTarget を返す。
    6. patternMatch"/" または "\" で分割したものが、"""."".."、または "node_modules" セグメントを、大文字小文字を区別せず、パーセントエンコードされたバリアントを含めて含む場合、Invalid Module Specifier エラーをスローする。
    7. resolvedTarget のすべての "*"patternMatch で置き換えたものの URL 解決結果を返す。
  2. そうでなく、target が null でないオブジェクトの場合、
    1. target が、ECMA-262 6.1.7 Array Index で定義されているインデックスプロパティキーを含む場合、Invalid Package Configuration エラーをスローする。
    2. target の各プロパティ p について、オブジェクトの挿入順に、
      1. p"default" と等しいか、conditionsp のエントリを含む場合、
        1. targetValuetargetp プロパティの値とする。
        2. resolvedPACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) の結果とする。
        3. resolvedundefined と等しい場合、ループを続ける。
        4. resolved を返す。
    3. undefined を返す。
  3. そうでなく、target が配列の場合、
    1. _target.length がゼロの場合、null を返す。
    2. target の各項目 targetValue について、以下を実行する
      1. resolvedPACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) の結果とし、任意の Invalid Package Target エラーでループを続ける。
      2. resolvedundefined の場合、ループを続ける。
      3. resolved を返す。
    3. 最後のフォールバック解決の null の戻り値またはエラーを返すかスローする。
  4. そうでなく、targetnull の場合、null を返す。
  5. それ以外の場合は Invalid Package Target エラーをスローする。

ESM_FILE_FORMAT(url)

  1. 表明: url は既存のファイルに対応する。
  2. url".mjs" で終わる場合、
    1. "module" を返す。
  3. url".cjs" で終わる場合、
    1. "commonjs" を返す。
  4. url".json" で終わる場合、
    1. "json" を返す。
  5. url".wasm" で終わる場合、
    1. "wasm" を返す。
  6. --experimental-addon-modules が有効で、かつ url".node" で終わる場合、
    1. "addon" を返す。
  7. packageURLLOOKUP_PACKAGE_SCOPE(url) の結果とする。
  8. pjsonREAD_PACKAGE_JSON(packageURL) の結果とする。
  9. packageTypenull とする。
  10. pjson?.type"module" または "commonjs" の場合、
    1. packageTypepjson.type に設定する。
  11. url".js" で終わる場合、
    1. packageTypenull でない場合、
      1. packageType を返す。
    2. DETECT_MODULE_SYNTAX(source) の結果が true の場合、
      1. "module" を返す。
    3. "commonjs" を返す。
  12. url に拡張子がない場合、
    1. packageType"module" であり、かつ url のファイルが WebAssembly モジュールの "application/wasm" コンテンツタイプヘッダーを含む場合、
      1. "wasm" を返す。
    2. packageTypenull でない場合、
      1. packageType を返す。
    3. DETECT_MODULE_SYNTAX(source) の結果が true の場合、
      1. "module" を返す。
    4. "commonjs" を返す。
  13. undefined を返す (読み込みフェーズでスローされる)。

LOOKUP_PACKAGE_SCOPE(url)

  1. scopeURLurl とする。
  2. scopeURL がファイルシステムのルートでない間、
    1. scopeURLscopeURL の親 URL に設定する。
    2. scopeURL"node_modules" パスセグメントで終わる場合、null を返す。
    3. pjsonURLscopeURL 内の "package.json" の解決結果とする。
    4. pjsonURL のファイルが存在する場合、
      1. scopeURL を返す。
  3. null を返す。

READ_PACKAGE_JSON(packageURL)

  1. pjsonURLpackageURL 内の "package.json" の解決結果とする。
  2. pjsonURL のファイルが存在しない場合、
    1. null を返す。
  3. packageURL のファイルが有効な JSON としてパースできない場合、
    1. Invalid Package Configuration エラーをスローする。
  4. pjsonURL のファイルのパースされた JSON ソースを返す。

DETECT_MODULE_SYNTAX(source)

  1. source を ECMAScript モジュールとしてパースする。
  2. パースが成功した場合、
    1. source がトップレベルの await、静的な import または export 文、または import.meta を含む場合、true を返す。
    2. source が CommonJS ラッパー変数 (require, exports, module, __filename, or __dirname) のいずれかのトップレベルのレキシカル宣言 (const, let, or class) を含む場合、true を返す。
  3. それ以外の場合は false を返す。

ESM 指定子解決アルゴリズムのカスタマイズ#

モジュールカスタマイズフックは、ESM 指定子解決アルゴリズムをカスタマイズするメカニズムを提供します。ESM 指定子に CommonJS スタイルの解決を提供する例として commonjs-extension-resolution-loader があります。