# 機能設計書 47-ESModuleチャンクローディング

## 概要

本ドキュメントは、ES Module環境向けのimport()方式チャンク読み込み機能について、ModuleChunkLoadingPluginおよびModuleChunkLoadingRuntimeModuleを中心に設計内容を記述する。

### 本機能の処理概要

本機能は、ES Module環境においてネイティブの動的import()構文を使用してチャンクを読み込むランタイムコードを生成する。ES Moduleの仕様に準拠したチャンク読み込みメカニズムを提供する。

**業務上の目的・背景**：モダンブラウザやNode.js ESM環境では、ネイティブのES Module import()が利用可能である。scriptタグベースのJSONP方式ではなく、ネイティブimport()を使用することで、HTTP/2との親和性やモジュールプリロードの最適化が可能になる。

**機能の利用シーン**：webpack設定の`output.chunkLoading`が`import`の場合に使用される。`output.module: true`でESM出力を行う場合のデフォルトチャンク読み込み方式。

**主要な処理内容**：
1. ModuleChunkLoadingPlugin: chunkLoading === "import" の場合にランタイムモジュールを登録
2. ModuleChunkLoadingRuntimeModule: import()によるチャンク読み込みランタイムコード生成
3. installChunk関数でESM形式のチャンクデータを処理
4. ExportWebpackRequireRuntimeModuleによるwebpack_requireのエクスポート

**関連システム・外部連携**：ModuleChunkFormatPlugin(ESMチャンクフォーマット)、ExportWebpackRequireRuntimeModule

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面との直接的な関連なし（ESM環境向け内部機構） |

## 機能種別

ランタイムコード生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| chunkId | ChunkId | Yes | 読み込むチャンクのID | - |
| promises | Promise[] | Yes | チャンク読み込みPromiseの配列 | - |

### 入力データソース

- __webpack_require__.e(chunkId)経由のチャンク読み込みリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ランタイムコード | string | import()読み込みのJavaScriptランタイムコード |

### 出力先

- webpackランタイムバンドル内

## 処理フロー

### 処理シーケンス

```
1. ModuleChunkLoadingPlugin.apply()
   └─ chunkLoading === "import" の場合に有効化
   └─ runtimeRequirementInTreeフックに登録

2. ensureChunkHandlers.j (チャンク読み込み)
   └─ installedChunks確認
   └─ import(publicPath + filename).then(installChunk) で動的読み込み
   └─ Promise.raceで読み込みとinstalledChunks登録を競合

3. installChunk (チャンクインストール)
   └─ __webpack_exports__.ids, __webpack_exports__.modules, __webpack_exports__.runtimeを分割代入
   └─ moduleFactoriesにモジュール登録
   └─ installedChunksを更新
```

### フローチャート

```mermaid
flowchart TD
    A[import呼び出し] --> B[__webpack_require__.e]
    B --> C[ensureChunkHandlers.j]
    C --> D{installedChunks状態?}
    D -->|0: loaded| E[完了]
    D -->|Array: loading| F[既存Promise返却]
    D -->|undefined: not loaded| G[import で読み込み]
    G --> H[installChunk]
    H --> I[moduleFactories登録]
    I --> J[installedChunks = 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | ESM形式チャンク | チャンクデータはESMの名前付きエクスポート(ids, modules, runtime)で提供 | 常時 |
| BR-47-02 | Promise.race | import()のPromiseとinstalledChunks登録のPromiseをraceで競合 | 常時 |
| BR-47-03 | 外部インストール | externalInstallChunkでSSR等の外部チャンク登録をサポート | 該当設定時 |
| BR-47-04 | auto publicPath | publicPathが"auto"の場合、import.meta.urlからの相対パスを使用 | publicPath="auto" |

### 計算ロジック

- baseURI: `new URL(rootOutputDir, import.meta.url)` で算出

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | import()によるチャンク読み込み失敗 | installedChunks[chunkId] = undefinedにリセット |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

該当なし

## パフォーマンス要件

- ネイティブimport()を使用するためブラウザの最適化恩恵を受ける
- Prefetch/Preloadはdocument.head.appendChild(link)で、ニュートラルプラットフォーム対応

## セキュリティ考慮事項

- crossOriginLoading設定によるCORS制御
- scriptNonceによるCSP対応

## 備考

- ESMチャンクフォーマットではRuntimeGlobals.esmIds/esmModules/esmRuntimeが使用される
- publicPathが"auto"の場合、import.meta.urlからの相対パスで解決される

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: プラグイン登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ModuleChunkLoadingPlugin.js | `lib/esm/ModuleChunkLoadingPlugin.js` | **24-143行目**: apply()でruntimeRequirementInTreeフックに登録 |
| 1-2 | ModuleChunkLoadingPlugin.js | `lib/esm/ModuleChunkLoadingPlugin.js` | **37行目**: chunkLoading === "import" の判定 |

#### Step 2: ランタイムコード生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ModuleChunkLoadingRuntimeModule.js | `lib/esm/ModuleChunkLoadingRuntimeModule.js` | **90-423行目**: generate()メソッド全体 |
| 2-2 | ModuleChunkLoadingRuntimeModule.js | `lib/esm/ModuleChunkLoadingRuntimeModule.js` | **166-199行目**: installChunk関数 |
| 2-3 | ModuleChunkLoadingRuntimeModule.js | `lib/esm/ModuleChunkLoadingRuntimeModule.js` | **202-254行目**: ensureChunkHandlers.j |

**主要処理フロー**:
- **179-184行目**: esmModulesのmoduleFactoriesへの登録
- **225-237行目**: import()呼び出しとinstallChunkのthen接続
- **238-241行目**: Promise.raceでinstalledChunksの登録

### プログラム呼び出し階層図

```
ModuleChunkLoadingPlugin.apply(compiler)
    |
    +-- compilation.hooks.runtimeRequirementInTree
    |       +-- handler()
    |               +-- compilation.addRuntimeModule(ModuleChunkLoadingRuntimeModule)
    |
    +-- compilation.hooks.additionalTreeRuntimeRequirements
            +-- chunkGraph.hasChunkEntryDependentChunks
                    +-- compilation.addRuntimeModule(ExportWebpackRequireRuntimeModule)

ModuleChunkLoadingRuntimeModule.generate()
    +-- installedChunks初期化
    +-- installChunk関数
    +-- ensureChunkHandlers.j
    +-- [HMR] loadUpdateChunk
    +-- [Prefetch/Preload] link要素生成
```

### データフロー図

```
[入力]                      [処理]                              [出力]

chunkId          ───▶  ensureChunkHandlers.j            ───▶  Promise<void>
                       ├─ installedChunks確認
                       └─ import(path + filename)
                             |
                             v (ESMモジュール)
                       installChunk(data)
                       ├─ data.ids (チャンクID配列)
                       ├─ data.modules (モジュールファクトリ)
                       └─ data.runtime (ランタイムコード)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ModuleChunkLoadingPlugin.js | `lib/esm/ModuleChunkLoadingPlugin.js` | ソース | プラグイン登録・有効化判定 |
| ModuleChunkLoadingRuntimeModule.js | `lib/esm/ModuleChunkLoadingRuntimeModule.js` | ソース | import()方式ランタイムコード生成 |
| ModuleChunkFormatPlugin.js | `lib/esm/ModuleChunkFormatPlugin.js` | ソース | ESMチャンクフォーマットプラグイン |
| ExportWebpackRequireRuntimeModule.js | `lib/esm/ExportWebpackRequireRuntimeModule.js` | ソース | webpack_requireのエクスポート |
