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

安定性: 2 - 安定

はじめに#

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ファイル拡張子、値が"module"package.json"type"フィールド、値が"module"--input-typeフラグ、または値が"module"--experimental-default-typeフラグを使用して、JavaScriptをESモジュールとして解釈するようにNode.jsに指示できます。これらは、コードがESモジュールとして実行されることを意図している明示的なマーカーです。

逆に、作成者は、.cjsファイル拡張子、値が"commonjs"package.json"type"フィールド、値が"commonjs"--input-typeフラグ、または値が"commonjs"--experimental-default-typeフラグを使用して、JavaScriptをCommonJSとして解釈するようにNode.jsに指示できます。

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

パッケージ#

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

import 指定子#

用語#

importステートメントの指定子は、import { sep } from 'node:path''node:path'など、fromキーワードの後の文字列です。指定子は、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ローダーを使用しない限り、'https://example.com/app.js'のような指定子は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'; 

インポート属性#

安定度: 1.1 - 開発中

この機能は以前は "インポートアサーション" と呼ばれており、with の代わりに assert キーワードを使用していました。以前の assert キーワードを使用しているコードは、代わりに with を使用するように更新する必要があります。

インポート属性提案は、モジュールインポートステートメントのインライン構文を追加し、モジュール指定子とともに詳細な情報を渡せるようにします。

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

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

Node.js は、以下の type 値をサポートしており、これらの属性は必須です。

属性 type必要となる対象
'json'JSON モジュール

組み込みモジュール#

コアモジュールは、パブリックAPIの名前付きエクスポートを提供します。また、CommonJSエクスポートの値であるデフォルトのエクスポートも提供されます。デフォルトのエクスポートは、特に、名前付きエクスポートの変更に使用できます。組み込みモジュールの名前付きエクスポートは、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 です。

import.meta.dirname#

安定度: 1.2 - リリース候補

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

import.meta.filename#

安定度: 1.2 - リリース候補

  • <string>現在のモジュールの完全な絶対パスとファイル名、および
  • シンボリックリンクが解決されたもの。
  • これは、url.fileURLToPath()と同じです。
  • import.meta.url.

注意点 ローカルモジュールのみがこのプロパティをサポートしています。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.resolve(specifier)#

安定度: 1.2 - リリース候補

  • 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()式は、ESモジュールをロードするためにCommonJSでサポートされています。

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

require#

CommonJSモジュールのrequireは、参照するファイルを常にCommonJSとして扱います。

ESモジュールは非同期実行であるため、ESモジュールをロードするためにrequireを使用することはサポートされていません。代わりに、CommonJSモジュールからESモジュールをロードするには、import()を使用してください。

CommonJS名前空間#

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

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

import { default as cjs } from 'cjs';

// The following import statement is "syntax sugar" (equivalent but sweeter)
// for `{ default as cjsSugar }` in the above import statement:
import cjsSugar from 'cjs';

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

CommonJSモジュールのECMAScriptモジュール名前空間表現は、常にCommonJSのmodule.exports値を指すdefaultエクスポートキーを持つ名前空間です。

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

import * as m from 'cjs';
console.log(m);
console.log(m === await import('cjs'));
// Prints:
//   [Module] { default: <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' }, name: 'exported' } 

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

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

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

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

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

requireexports、またはmodule.exportsなし#

ほとんどの場合、ESモジュールのimportを使用してCommonJSモジュールをロードできます。

必要な場合は、module.createRequire()を使用して、ESモジュール内にrequire関数を作成できます。

__filenameまたは__dirnameなし#

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

__filenameおよび__dirnameのユースケースは、import.meta.filenameおよびimport.meta.dirnameを介して複製できます。

アドオンロードなし#

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

代わりに、module.createRequire()またはprocess.dlopenでロードできます。

require.resolveなし#

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

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

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

NODE_PATHなし#

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

require.extensionsなし#

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

require.cacheなし#

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

JSONモジュール#

安定度: 1 - 実験的

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

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

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

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

Wasmモジュール#

安定度: 1 - 実験的

WebAssemblyモジュールのインポートは、--experimental-wasm-modulesフラグの下でサポートされており、すべての.wasmファイルを通常のモジュールとしてインポートできるようになり、モジュールインポートもサポートされます。

この統合は、WebAssemblyのESモジュール統合提案に沿ったものです。

たとえば、以下を含むindex.mjsがあるとします。

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

以下で実行すると

node --experimental-wasm-modules index.mjs 

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

トップレベルの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`
}); 

HTTPSおよびHTTPインポート#

安定度: 1 - 実験的

https:およびhttp:を使用してネットワークベースのモジュールをインポートすることは、--experimental-network-importsフラグの下でサポートされています。これにより、WebブラウザのようなインポートがNode.jsで動作するようになります。ただし、ブラウザサンドボックスではなく特権環境で実行する場合、アプリケーションの安定性とセキュリティに関する懸念が異なるため、いくつかの違いがあります。

インポートはHTTP/1に制限されています#

HTTP/2およびHTTP/3の自動プロトコルネゴシエーションはまだサポートされていません。

HTTPはループバックアドレスに制限されています#

http:は中間者攻撃に対して脆弱であるため、IPv4アドレス127.0.0.0/8127.0.0.1から127.255.255.255)とIPv6アドレス::1の範囲外のアドレスには使用できません。http:のサポートは、ローカル開発で使用することを目的としています。

認証は宛先サーバーに送信されません。#

AuthorizationCookie、およびProxy-Authorizationヘッダーはサーバーに送信されません。インポートされたURLの一部にユーザー情報を含めることは避けてください。サーバー上でこれらを安全に使用するためのセキュリティモデルが検討されています。

CORSは宛先サーバーでチェックされません#

CORSは、APIのコンシューマーを特定のホストセットに制限できるように設計されています。これは、サーバーベースの実装では意味がないため、サポートされていません。

ネットワーク以外の依存関係を読み込むことはできません#

これらのモジュールは、http:またはhttps:を介していない他のモジュールにアクセスできません。セキュリティ上の懸念を回避しながらローカルモジュールにアクセスするには、ローカル依存関係への参照を渡します。

// file.mjs
import worker_threads from 'node:worker_threads';
import { configure, resize } from 'https://example.com/imagelib.mjs';
configure({ worker_threads }); 
// https://example.com/imagelib.mjs
let worker_threads;
export function configure(opts) {
  worker_threads = opts.worker_threads;
}
export function resize(img, size) {
  // Perform resizing in worker_thread to avoid main thread blocking
} 

ネットワークベースのロードはデフォルトで有効になっていません#

当面の間、http:またはhttps:を介してリソースをロードするには、--experimental-network-importsフラグが必要です。将来的には、これを強制するために別のメカニズムが使用されます。Node.jsアプリケーションの信頼性に影響を与える可能性のある可変状態を、推移的な依存関係が誤って使用するのを防ぐために、オプトインが必要です。

ローダー#

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

解決とロードアルゴリズム#

機能#

デフォルトのリゾルバーには、以下のプロパティがあります。

  • ESモジュールで使用されているFileURLベースの解決
  • 相対URLおよび絶対URL解決
  • デフォルトの拡張子なし
  • フォルダーのメインなし
  • node_modulesを介したベアスペシファイアパッケージ解決ルックアップ
  • 不明な拡張子またはプロトコルでの失敗なし
  • ロードフェーズへのフォーマットのヒントをオプションで提供できます

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

  • node: URLを介した組み込みモジュールのロードのサポート
  • data: URLを介した「インライン」モジュールのロードのサポート
  • file:モジュールのロードのサポート
  • 他のURLプロトコルでの失敗
  • file:ロードでの不明な拡張子での失敗(.cjs.js、および.mjsのみをサポート)

解決アルゴリズム#

ESモジュールスペシファイアをロードするアルゴリズムは、以下のESM_RESOLVEメソッドを通じて提供されます。これは、親URLに対するモジュールスペシファイアの解決済みURLを返します。

解決アルゴリズムは、モジュールロードの完全な解決済みURLと、推奨されるモジュール形式を決定します。解決アルゴリズムは、解決済みURLプロトコルをロードできるかどうか、またはファイル拡張子が許可されているかどうかを決定しません。代わりに、これらの検証は、ロードフェーズ中にNode.jsによって適用されます(たとえば、file:data:node:ではないプロトコルを持つURLをロードするように要求された場合、または--experimental-network-importsが有効な場合、https:)。

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

解決されたURLのモジュール形式を決定するアルゴリズムは、ESM_FILE_FORMATによって提供され、すべてのファイルの一意のモジュール形式を返します。ECMAScriptモジュールの場合、"module"形式が返され、レガシーCommonJSローダーを介したロードを示すために"commonjs"形式が使用されます。今後のアップデートでは、"addon"などの追加形式を拡張できます。

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

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

リゾルバーは、以下のエラーをスローできます。

  • 無効なモジュールスペシファイア:モジュールスペシファイアが無効なURL、パッケージ名、またはパッケージサブパススペシファイアです。
  • 無効なパッケージ構成:package.json構成が無効であるか、無効な構成が含まれています。
  • 無効なパッケージターゲット:パッケージのエクスポートまたはインポートは、無効な型または文字列ターゲットであるパッケージのターゲットモジュールを定義します。
  • パッケージパスがエクスポートされていません:パッケージのエクスポートは、特定のモジュールのパッケージ内のターゲットサブパスを定義または許可していません。
  • パッケージインポートが定義されていません:パッケージのインポートは、スペシファイアを定義していません。
  • モジュールが見つかりません:要求されたパッケージまたはモジュールが存在しません。
  • サポートされていないディレクトリインポート:解決されたパスがディレクトリに対応しており、これはモジュールインポートのサポートされているターゲットではありません。

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

ESM_RESOLVE(specifier, parentURL)

  1. resolvedundefinedにします。
  2. specifierが有効なURLである場合、
    1. resolvedを、URLとしてspecifierを解析および再シリアル化した結果に設定します。
  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. 無効なモジュールスペシファイアエラーをスローします。
    2. resolvedにあるファイルがディレクトリである場合、
      1. サポートされていないディレクトリインポートエラーをスローします。
    3. resolvedにあるファイルが存在しない場合、
      1. モジュールが見つかりませんエラーをスローします。
    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. 無効なモジュールスペシファイアエラーをスローします。
  3. packageSpecifierがNode.js組み込みモジュール名である場合、
    1. 文字列"node:"packageSpecifierを連結したものを返します。
  4. packageSpecifier"@"で始まらない場合、
    1. packageNameを、最初の"/"セパレーターまたは文字列の終わりまでのpackageSpecifierのサブストリングに設定します。
  5. それ以外の場合、
    1. packageSpecifier"/"セパレーターが含まれていない場合、
      1. 無効なモジュールスペシファイアエラーをスローします。
    2. packageNameを、2番目の"/"セパレーターまたは文字列の終わりまでのpackageSpecifierのサブストリングに設定します。
  6. packageName"."で始まるか、"\"または"%"が含まれている場合、
    1. 無効なモジュールスペシファイアエラーをスローします。
  7. packageSubpathを、"."と、packageNameの長さの位置から始まるpackageSpecifierのサブストリングを連結したものにします。
  8. packageSubpath"/"で終わる場合、
    1. 無効なモジュールスペシファイアエラーをスローします。
  9. selfUrlを、PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)の結果にします。
  10. selfUrlundefinedでない場合は、selfUrlを返します。
  11. parentURLがファイルシステムのルートではない間、
    1. packageURLを、parentURLに対する、"node_modules/"packageSpecifierを連結したもののURL解決にします。
    2. parentURLを、parentURLの親フォルダーURLに設定します。
    3. packageURLにあるフォルダーが存在しない場合、
      1. 次のループ反復を続行します。
    4. pjsonを、READ_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解決を返します。
  12. モジュールが見つかりませんエラーをスローします。

PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)

  1. packageURLを、LOOKUP_PACKAGE_SCOPE(parentURL)の結果にします。
  2. packageURLnullである場合、
    1. undefinedを返します。
  3. pjsonを、READ_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)

  1. exports が、"." で始まるキーと、"." で始まらないキーの両方を持つオブジェクトである場合、不正なパッケージ構成エラーをスローします。
  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_IMPORTS_RESOLVE(specifier, parentURL, conditions)

  1. アサート: specifier"#" で始まります。
  2. specifier"#" に完全に等しいか、"#/" で始まる場合、
    1. 無効なモジュールスペシファイアエラーをスローします。
  3. packageURLを、LOOKUP_PACKAGE_SCOPE(parentURL)の結果にします。
  4. packageURLnull でない場合、
    1. pjsonを、READ_PACKAGE_JSON(packageURL)の結果にします。
    2. pjson.imports が非 null のオブジェクトである場合、
      1. resolvedPACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) の結果とします。
      2. resolvednull または undefined でない場合、resolved を返します。
  5. パッケージインポートが定義されていませんエラーをスローします。

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

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

PATTERN_KEY_COMPARE(keyA, keyB)

  1. アサート: keyA"/" で終わるか、単一の "*" のみを含みます。
  2. アサート: keyB"/" で終わるか、単一の "*" のみを含みます。
  3. baseLengthA を、keyA"*" が含まれる場合は keyA"*" のインデックスに 1 を加えたもの、それ以外の場合は keyA の長さとします。
  4. baseLengthB を、keyB"*" が含まれる場合は keyB"*" のインデックスに 1 を加えたもの、それ以外の場合は keyB の長さとします。
  5. baseLengthAbaseLengthB より大きい場合は -1 を返します。
  6. baseLengthBbaseLengthA より大きい場合は 1 を返します。
  7. keyA"*" が含まれない場合は 1 を返します。
  8. keyB"*" が含まれない場合は -1 を返します。
  9. keyA の長さが keyB の長さより大きい場合は -1 を返します。
  10. keyB の長さが keyA の長さより大きい場合は 1 を返します。
  11. 0 を返します。

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

  1. target が文字列の場合、
    1. target"./" で始まらない場合、
      1. isImportsfalse の場合、または target"../" または "/" で始まる場合、または target が有効な URL の場合、
        1. 不正なパッケージターゲットエラーをスローします。
      2. patternMatch が文字列の場合、
        1. PACKAGE_RESOLVE("*" のすべてのインスタンスが patternMatch に置き換えられた target, packageURL + "/") を返します。
      3. PACKAGE_RESOLVE(target, packageURL + "/") を返します。
    2. target"/" または "\" で分割したものが、最初の "." セグメントの後、大文字と小文字を区別せず、パーセントエンコードされたバリアントを含め、"""."".."、または "node_modules" セグメントを含む場合、不正なパッケージターゲットエラーをスローします。
    3. resolvedTargetpackageURLtarget の連結の URL 解決とします。
    4. アサート: packageURLresolvedTarget に含まれています。
    5. patternMatchnull の場合、
      1. resolvedTarget を返します。
    6. patternMatch"/" または "\" で分割したものが、大文字と小文字を区別せず、パーセントエンコードされたバリアントを含め、"""."".."、または "node_modules" セグメントを含む場合、不正なモジュール指定子エラーをスローします。
    7. "*" のすべてのインスタンスが patternMatch に置き換えられた resolvedTarget の URL 解決を返します。
  2. そうではなく、target が非 null オブジェクトの場合、
    1. target が、ECMA-262 6.1.7 配列インデックス で定義されているようなインデックスプロパティキーを含む場合、不正なパッケージ構成エラーをスローします。
    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. Invalid Package Target エラーが発生した場合はループを継続し、resolvedPACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) の結果とします。
      2. resolvedundefined の場合、ループを続けます。
      3. resolved を返します。
    3. 最後のフォールバック解決の null 戻り値またはエラーを返すかスローします。
  4. そうではなく、targetnull の場合、null を返します。
  5. それ以外の場合、不正なパッケージターゲットエラーをスローします。

ESM_FILE_FORMAT(url)

  1. アサート: url は既存のファイルに対応します。
  2. url".mjs" で終わる場合、
    1. "module" を返します。
  3. url".cjs" で終わる場合、
    1. "commonjs" を返します。
  4. url".json" で終わる場合、
    1. "json" を返します。
  5. --experimental-wasm-modules が有効で、url".wasm" で終わる場合、
    1. "wasm" を返します。
  6. packageURLLOOKUP_PACKAGE_SCOPE(url) の結果とします。
  7. pjsonを、READ_PACKAGE_JSON(packageURL)の結果にします。
  8. packageTypenull とします。
  9. pjson?.type"module" または "commonjs" の場合、
    1. packageTypepjson.type に設定します。
  10. url".js" で終わる場合、
    1. packageTypenull でない場合、
      1. packageType を返します。
    2. --experimental-detect-module が有効で、モジュールのソースに静的インポートまたはエクスポート構文が含まれている場合、
      1. "module" を返します。
    3. "commonjs" を返します。
  11. url に拡張子がない場合、
    1. packageType"module" で、--experimental-wasm-modules が有効で、url のファイルに WebAssembly モジュールのヘッダーが含まれている場合、
      1. "wasm" を返します。
    2. packageTypenull でない場合、
      1. packageType を返します。
    3. --experimental-detect-module が有効で、モジュールのソースに静的インポートまたはエクスポート構文が含まれている場合、
      1. "module" を返します。
    4. "commonjs" を返します。
  12. 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. 不正なパッケージ構成エラーをスローします。
  4. pjsonURL のファイルの解析された JSON ソースを返します。

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

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