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

## 概要

本ドキュメントは、webpackのブラウザ環境向けJSONP方式チャンク動的読み込み機能について、JsonpChunkLoadingPluginおよびJsonpChunkLoadingRuntimeModuleを中心に設計内容を記述する。

### 本機能の処理概要

本機能は、ブラウザ環境においてJSONP(script tag)方式でチャンクを動的に読み込むランタイムコードを生成する。コード分割(code splitting)により生成された非同期チャンクの遅延読み込みを実現する。

**業務上の目的・背景**：SPAやマイクロフロントエンドアプリケーションでは、初期読み込みサイズを最小化するためにコード分割が不可欠である。JSONP方式は、ブラウザのscriptタグを利用してチャンクを読み込む最も広くサポートされた方法であり、CORSの制約を受けにくい。

**機能の利用シーン**：webpack設定の`output.chunkLoading`が`jsonp`（ブラウザターゲットのデフォルト）の場合に使用される。import()による動的インポートやSplitChunksPluginで分割されたチャンクの読み込みに利用される。

**主要な処理内容**：
1. installedChunksオブジェクトでチャンク読み込み状態を管理
2. scriptタグ生成によるチャンクのダウンロード
3. webpackJsonpCallback関数でチャンクデータの受信・処理
4. Prefetch/Preloadのlink要素生成
5. HMR(Hot Module Replacement)更新チャンクの読み込み

**関連システム・外部連携**：LoadScriptRuntimeModule(スクリプト読み込み)、EnsureChunkRuntimeModule(チャンクロード制御)、HMR機能(No.34-36)

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | Page A (hybrid-routing) | 補助機能 | ブラウザ環境での動的チャンク読み込みランタイム |
| 9 | Page B (hybrid-routing) | 補助機能 | ブラウザ環境での動的チャンク読み込みランタイム |

## 機能種別

ランタイムコード生成

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ランタイムコード | string | JSONP読み込みのJavaScriptランタイムコード |
| installedChunks | object | チャンク状態管理オブジェクト |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. installedChunks初期化
   └─ 初期チャンク: 0 (loaded), 未ロード: undefined
   └─ ロード中: [resolve, reject, Promise]

2. ensureChunkHandlers.j (チャンク読み込み)
   └─ installedChunksを確認
   └─ Promiseを生成しinstalledChunksに登録
   └─ LoadScript(url, loadingEnded, key, chunkId)で読み込み開始

3. webpackJsonpCallback (チャンクデータ受信)
   └─ chunkIds, moreModules, runtimeを受信
   └─ moduleFactoriesにモジュールを登録
   └─ runtimeを実行
   └─ installedChunks[chunkId][0]() でPromiseをresolve

4. chunkLoadingGlobal.push = webpackJsonpCallback
   └─ グローバル配列のpushを上書きしてコールバック化
```

### フローチャート

```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[新規Promiseを作成]
    G --> H[scriptタグでチャンク読み込み]
    H --> I[webpackJsonpCallback]
    I --> J[moduleFactoriesにモジュール登録]
    J --> K[Promiseをresolve]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | チャンク状態管理 | undefined=未ロード, null=prefetched, [resolve,reject,Promise]=ロード中, 0=ロード済 | 常時 |
| BR-45-02 | グローバルコールバック | chunkLoadingGlobalのpush関数を上書きして受信コールバック化 | 常時 |
| BR-45-03 | エラーハンドリング | loadingEnded関数でタイムアウト/ネットワークエラーを検出しreject | ロード失敗時 |
| BR-45-04 | Prefetch/Preload | link要素(rel=prefetch/preload)でチャンクの先読み | 該当設定時 |

### 計算ロジック

特になし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ChunkLoadError | Error | チャンク読み込み失敗(タイムアウト/ネットワーク) | error.type=errorType, error.request=realSrcを設定 |
| ChunkLoadError | Error | missing(スクリプトのloadイベントだがチャンク未登録) | エラーとして処理 |

### リトライ仕様

標準ではリトライは行わない。

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

該当なし

## パフォーマンス要件

- chunkLoadTimeout(output.chunkLoadTimeout)でタイムアウト制御
- fetchPriority属性によるブラウザのリソース優先度制御
- Prefetch/Preloadによる先読みで知覚パフォーマンスを向上

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

- crossOriginLoading設定によるCORS制御
- scriptNonceによるCSP(Content Security Policy)対応
- TrustedTypes対応(createScriptUrl)

## 備考

- chunkLoadingGlobalのデフォルト値は`webpackChunk` + uniqueName
- HMR更新チャンクはhotUpdateGlobal経由で別途処理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | JsonpChunkLoadingPlugin.js | `lib/web/JsonpChunkLoadingPlugin.js` | **23-98行目**: apply()でruntimeRequirementInTreeフックに登録 |
| 1-2 | JsonpChunkLoadingPlugin.js | `lib/web/JsonpChunkLoadingPlugin.js` | **30-37行目**: isEnabledForChunk - chunkLoading === "jsonp" の判定 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | JsonpChunkLoadingRuntimeModule.js | `lib/web/JsonpChunkLoadingRuntimeModule.js` | **79-452行目**: generate()メソッド全体 |
| 2-2 | JsonpChunkLoadingRuntimeModule.js | `lib/web/JsonpChunkLoadingRuntimeModule.js` | **133-148行目**: installedChunks初期化 |
| 2-3 | JsonpChunkLoadingRuntimeModule.js | `lib/web/JsonpChunkLoadingRuntimeModule.js` | **149-220行目**: ensureChunkHandlers.j - チャンク読み込みロジック |
| 2-4 | JsonpChunkLoadingRuntimeModule.js | `lib/web/JsonpChunkLoadingRuntimeModule.js` | **401-449行目**: webpackJsonpCallback - チャンクデータ受信処理 |

**主要処理フロー**:
- **172-177行目**: Promiseの作成とinstalledChunksへの登録
- **179行目**: URL生成(publicPath + getChunkScriptFilename)
- **182-203行目**: loadingEnded関数(エラーハンドリング)
- **204-208行目**: loadScript呼び出し
- **446-448行目**: chunkLoadingGlobal.pushをwebpackJsonpCallbackにバインド

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

```
JsonpChunkLoadingPlugin.apply(compiler)
    |
    +-- compilation.hooks.runtimeRequirementInTree
            +-- for(ensureChunkHandlers) -> handler
            +-- for(hmrDownloadUpdateHandlers) -> handler
            +-- for(baseURI) -> handler
            |
            +-- handler()
                    +-- compilation.addRuntimeModule(JsonpChunkLoadingRuntimeModule)
                            |
                            +-- generate()
                                    +-- installedChunks初期化コード
                                    +-- ensureChunkHandlers.j コード
                                    +-- webpackJsonpCallback コード
                                    +-- [HMR] loadUpdateChunk コード
                                    +-- [Prefetch/Preload] link要素生成コード
```

### データフロー図

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

chunkId           ───▶  ensureChunkHandlers.j        ───▶  Promise<void>
                        ├─ installedChunks確認
                        ├─ scriptタグ生成
                        └─ loadScript(url)
                              |
                              v (ネットワーク)
                        webpackJsonpCallback
                        ├─ moduleFactories登録
                        ├─ runtime実行
                        └─ Promise resolve
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JsonpChunkLoadingPlugin.js | `lib/web/JsonpChunkLoadingPlugin.js` | ソース | プラグイン登録・有効化判定 |
| JsonpChunkLoadingRuntimeModule.js | `lib/web/JsonpChunkLoadingRuntimeModule.js` | ソース | ランタイムコード生成 |
| JsonpTemplatePlugin.js | `lib/web/JsonpTemplatePlugin.js` | ソース | JSONPテンプレートプラグイン |
| LoadScriptRuntimeModule.js | `lib/runtime/LoadScriptRuntimeModule.js` | ソース | scriptタグ読み込みランタイム |
| EnsureChunkRuntimeModule.js | `lib/runtime/EnsureChunkRuntimeModule.js` | ソース | チャンクロード制御ランタイム |
