# 帳票設計書 8-react-loadable-manifest.json

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `react-loadable-manifest.json` の設計を記述する。このマニフェストは、`React.lazy` / `next/dynamic` による動的インポート（`import()`）のチャンク情報を管理する。

### 本帳票の処理概要

react-loadable-manifest.json は、`ReactLoadablePlugin`（Webpackプラグイン）によって生成されるJSONファイルである。アプリケーション内の `import()` による動的インポートを検出し、各動的インポートに対応するチャンクファイル（JS/CSS）とモジュールIDのマッピングを提供する。これにより、SSR時に動的コンポーネントの依存チャンクを事前に特定し、クライアントに適切なスクリプトタグを生成できる。

**業務上の目的・背景**：`next/dynamic` や `React.lazy` で動的にインポートされるコンポーネントは、コード分割により別チャンクに分離される。SSR時にこれらのコンポーネントをレンダリングした場合、対応するクライアント側チャンクをHTMLに含める必要がある。本マニフェストはこの対応関係を管理し、SSRとクライアントのハイドレーションが正しく連携できるようにする。

**帳票の利用シーン**：SSR時の動的コンポーネントの依存チャンク特定、クライアント側でのプリロード対象チャンクの決定、Edgeランタイムでの動的コンポーネント処理に使用される。

**主要な出力内容**：
1. 動的インポートのキー（`originFile -> importRequest` 形式）とモジュールID・ファイルリストのマッピング
2. 各動的インポートに対応するJS/CSSチャンクファイル名

**帳票の出力タイミング**：`next build` コマンド実行時のWebpackコンパイルプロセス中、`PROCESS_ASSETS_STAGE_ADDITIONS` ステージでReactLoadablePluginが実行された際に出力される。

**帳票の利用者**：Next.jsサーバーランタイム（SSR時のチャンク解決）、Edgeランタイム（`middleware-react-loadable-manifest.js` 経由）、クライアントサイドランタイム。

## 帳票種別

ビルドマニフェスト（JSON形式の動的インポートチャンクマッピングファイル）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `next build` | ビルドコマンド実行 |
| N/A | 開発サーバー | `next dev` | 開発サーバー起動・ファイル変更時 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | `react-loadable-manifest.json` |
| 出力方法 | `compilation.emitAsset` 経由（`.next/react-loadable-manifest.json`） |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

フラットなJSONオブジェクトで、動的インポートのキーをプロパティ名、モジュールID・ファイルリストを値とする。

```
{
  "src/components/Heavy.tsx -> ./HeavyComponent": {
    "id": "123",
    "files": [
      "static/chunks/HeavyComponent-abc123.js",
      "static/css/HeavyComponent-def456.css"
    ]
  },
  "pages/index.tsx -> ../components/Modal": {
    "id": "456",
    "files": [
      "static/chunks/Modal-ghi789.js"
    ]
  }
}
```

### ヘッダー部

N/A（フラットなKey-Valueマッピング）

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | キー | `${originFile相対パス} -> ${importRequest}` | `path.relative(projectSrcDir, originRequest)` + ` -> ` + `dependency.request` | 文字列 | N/A |
| 2 | id | モジュールID | 開発時: キー文字列、本番: `compilation.chunkGraph.getModuleId(module)` | 文字列/数値 | N/A |
| 3 | files | 必要なJS/CSSファイルリスト | チャンクグループのチャンクファイル（`static/(chunks\|css)/`にマッチ） | 文字列配列 | N/A |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| import()依存 | `dependency.type` が `import()` で始まること | Yes |
| ファイル形式 | `.js` または `.css` で終わり、`static/(chunks\|css)/` にマッチするファイルのみ | Yes |
| projectSrcDir | pagesDir/appDirの親ディレクトリが必要 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | キー（マニフェストのプロパティ名） | 昇順（アルファベット順） |

### 改ページ条件

N/A

## データベース参照仕様

N/A

### テーブル別参照項目詳細

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| キー文字列 | `path.relative(projectSrcDir, originRequest) + " -> " + dependency.request` | N/A | originRequestはimport()を含むファイル |
| projectSrcDir | `path.dirname(pagesOrAppDir)` | N/A | pagesDir/appDirの親ディレクトリ |
| モジュールID（開発時） | キー文字列そのまま | N/A | 開発時はreadableな文字列ID |
| モジュールID（本番） | `compilation.chunkGraph.getModuleId(module)` | N/A | 本番は数値ID |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Webpackコンパイル開始] --> B[ReactLoadablePlugin.apply]
    B --> C[compilation.hooks.processAssets.tap]
    C --> D[createAssets実行]
    D --> E[buildManifest関数呼び出し]
    E --> F[全モジュールのblocksをイテレート]
    F --> G{import依存か?}
    G -->|Yes| H[originモジュール・依存モジュール取得]
    G -->|No| I[スキップ]
    H --> J[キー文字列構築]
    J --> K[チャンクグループからファイルリスト収集]
    K --> L[manifest にエントリ追加]
    L --> M[キーでソート]
    M --> N[react-loadable-manifest.json出力]
    N --> O{runtimeAsset指定あり?}
    O -->|Yes| P[middleware-react-loadable-manifest.js出力]
    O -->|No| Q[終了]
    P --> Q
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| projectSrcDir未定義 | pagesDir/appDirが未設定 | N/A（空マニフェスト返却） | ページディレクトリ設定の確認 |
| モジュール未解決 | import()の対象モジュールが見つからない | N/A（スキップ） | インポートパスの確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 動的インポート数に依存（通常は数十件） |
| 目標出力時間 | Webpackコンパイル時間内 |
| 同時出力数上限 | 1 |

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

ソースファイルの相対パスがキーとして露出するため、アプリケーションのファイル構造が推測可能になる。`.next/` ディレクトリの外部非公開が必要。Edgeランタイム向けの `middleware-react-loadable-manifest.js` は `self.__REACT_LOADABLE_MANIFEST` に設定され、JSONの二重シリアライズが行われる。

## 備考

- React Loadable（James Kyle氏のライブラリ）のPR #132をベースに、Next.js用にカスタマイズされた実装
- `import(/* webpackMode: "eager" */ ...)` や `import(\`...\`)` （テンプレートリテラル）はサポートされない
- `shouldCreateDynamicCssManifest` が true の場合（Pages Dir + Production + Webpack）、`dynamic-css-manifest.json` も同時生成される
- 同一モジュールが複数のチャンクグループで参照される場合、ファイルリストがマージされる

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | load-components.ts | `packages/next/src/server/load-components.ts` | `ReactLoadableManifest`型定義。`{ [key: string]: { id: string\|number, files: string[] } }` |
| 1-2 | constants.ts | `packages/next/src/shared/lib/constants.ts` | `REACT_LOADABLE_MANIFEST`定数（107行目） |

**読解のコツ**: ReactLoadableManifestの型はload-components.tsで定義されている。キーの構造（`originFile -> request`）はプラグイン内で構築される。

#### Step 2: プラグイン実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | react-loadable-plugin.ts | `packages/next/src/build/webpack/plugins/react-loadable-plugin.ts` | `ReactLoadablePlugin`クラス（168〜252行目）とbuildManifest関数（57〜166行目） |

**主要処理フロー**:
1. **239〜250行目**: `apply`メソッドで`processAssets` hookに登録
2. **189〜200行目**: `createAssets`メソッドでbuildManifest呼び出し、結果をemitAsset
3. **84〜152行目**: `handleBlock`関数で全モジュールの依存ブロックを再帰走査
4. **88行目**: `dependency.type.startsWith('import()')` でimport()依存をフィルタ
5. **104行目**: キー文字列 `${relative(projectSrcDir, originRequest)} -> ${dependency.request}` を構築
6. **126〜141行目**: チャンクグループからJS/CSSファイルを収集
7. **148〜149行目**: マニフェストエントリにid/filesをセット

#### Step 3: 出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | react-loadable-plugin.ts | `packages/next/src/build/webpack/plugins/react-loadable-plugin.ts` | 202〜236行目。JSON出力、runtimeAsset出力、dynamic-css-manifest出力 |

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

```
next build
    |
    +-- Webpack compilation
            |
            +-- ReactLoadablePlugin.apply() [239行目]
                    |
                    +-- createAssets() [189行目]
                            |
                            +-- buildManifest() [57行目]
                            |       |
                            |       +-- handleBlock() [84行目] (再帰)
                            |       |       +-- getModuleFromDependency()
                            |       |       +-- getOriginModuleFromDependency()
                            |       |       +-- getChunkGroupFromBlock()
                            |       |
                            |       +-- ソート [157〜160行目]
                            |
                            +-- compilation.emitAsset(react-loadable-manifest.json)
                            |
                            +-- compilation.emitAsset(middleware-react-loadable-manifest.js) [runtimeAsset時]
                            |
                            +-- compilation.emitAsset(dynamic-css-manifest.json) [Pages+Prod時]
```

### データフロー図

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

Webpack modules               buildManifest()
  (import() dependencies) ---> handleBlock再帰走査
  chunk groups --------------> ファイルリスト収集
  module IDs ----------------> ID割り当て
                                    |
                                    +-- JSON.stringify --------> .next/react-loadable-manifest.json
                                    +-- self.__REACT_LOADABLE -> .next/server/middleware-react-loadable-manifest.js
                                    +-- (条件付き) -----------> .next/server/dynamic-css-manifest.json
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| react-loadable-plugin.ts | `packages/next/src/build/webpack/plugins/react-loadable-plugin.ts` | ソース | ReactLoadablePlugin実装 |
| load-components.ts | `packages/next/src/server/load-components.ts` | ソース | ReactLoadableManifest型定義 |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | REACT_LOADABLE_MANIFEST定数 |
| render.tsx | `packages/next/src/server/render.tsx` | ソース | SSR時のマニフェスト利用 |
| manifest-loader.ts | `packages/next/src/shared/lib/turbopack/manifest-loader.ts` | ソース | Turbopack用のマニフェストローダー |
