# 帳票設計書 2-pages-manifest.json

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `pages-manifest.json` の設計を記述する。このマニフェストは、Pagesルーター用のページパスとサーバー側のJavaScriptファイルパスの対応関係を管理する。

### 本帳票の処理概要

pages-manifest.json は、Next.jsのWebpackビルドにおいて `PagesManifestPlugin` によって生成されるJSONファイルである。各ページのルートパス（例: `/`, `/about`）と、そのページをサーバーサイドでレンダリングするために必要なJavaScriptファイルのパスをマッピングする。

**業務上の目的・背景**：Next.jsのサーバーは、リクエストされたURLに対応するページコンポーネントをロードしてレンダリングする必要がある。pages-manifest.jsonは、URLパスからサーバー側の実際のJSファイルへの変換テーブルとして機能し、SSR・SSG・APIルートのルーティング解決に不可欠な役割を果たす。

**帳票の利用シーン**：サーバー起動時のルーティングテーブル構築、リクエスト処理時のページコンポーネントファイル解決、`next export` 実行時のデフォルトパスマップ生成、開発サーバーでのページ検出に使用される。

**主要な出力内容**：
1. ページルートパスとサーバー側JSファイルパスのキー・値ペア
2. PagesルーターとApp Router両方のページエントリ（App Routerは`app-paths-manifest.json`に分離）
3. Node.jsサーバーとEdgeサーバー双方のページ情報をマージした統合マニフェスト

**帳票の出力タイミング**：`next build` コマンド実行時のWebpackコンパイルプロセス中、`PROCESS_ASSETS_STAGE_ADDITIONS` ステージでPagesManifestPluginが実行された際に出力される。Node.jsサーバーコンパイラとEdgeサーバーコンパイラの両方から生成され、結果がマージされる。

**帳票の利用者**：Next.jsサーバーランタイム（ページコンポーネントのロード）、`next export`（静的HTML生成時のパスマップ）、開発サーバー（ページルーティング）。

## 帳票種別

ビルドマニフェスト（JSON形式のルーティングマッピングファイル）

## 利用画面

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

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | `pages-manifest.json` |
| 出力方法 | ファイルシステムへの書き出し（`.next/server/pages-manifest.json`） |
| 文字コード | UTF-8 |

### PDF固有設定

N/A（JSON形式のため該当なし）

### Excel固有設定

N/A（JSON形式のため該当なし）

## 帳票レイアウト

### レイアウト概要

pages-manifest.json はフラットなJSONオブジェクトとして構成され、ページパスをキー、サーバー側JSファイルパスを値とする。

```
{
  "/": "pages/index.js",
  "/about": "pages/about.js",
  "/api/hello": "pages/api/hello.js",
  "/_app": "pages/_app.js",
  "/_document": "pages/_document.js",
  "/_error": "pages/_error.js"
}
```

### ヘッダー部

N/A（フラットなKey-Valueマッピングのため、ヘッダー・明細の区分なし）

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ページパス（キー） | ルートパス（例: `/`, `/about`） | `getRouteFromEntrypoint(entrypoint.name)` の返却値 | 文字列 | N/A |
| 2 | ファイルパス（値） | サーバー側JSファイルの相対パス | エントリポイントの最後の`.js`ファイル（webpack-runtime除外後） | 文字列 | N/A |

### フッター部

N/A（JSONファイルのため該当なし）

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| エントリポイントフィルタ | `getRouteFromEntrypoint`でパスに変換できないエントリは除外 | Yes |
| ファイル形式フィルタ | `webpack-runtime`と`webpack-api-runtime`を含むファイルは除外、`.js`ファイルのみ | Yes |
| 空エントリフィルタ | ファイルが0件のエントリはスキップ | Yes |
| App Routerエントリ分離 | `entrypoint.name`が`app/`で始まるエントリは`app-paths-manifest.json`に分離 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| N/A | ソート指定なし | エントリポイント処理順 |

### 改ページ条件

N/A（JSONファイルのため該当なし）

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

### 参照テーブル一覧

N/A（データベースではなくWebpackコンパイル結果から取得）

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ファイルパス | 本番ビルド・Node.jsランタイム時: `file.slice(3)`（先頭3文字除去） | N/A | 開発モードまたはEdgeランタイム時はスライスしない |
| パス正規化 | `normalizePathSep(file)` でバックスラッシュをフォワードスラッシュに変換 | N/A | Windows互換性のため |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Webpackコンパイル開始] --> B[PagesManifestPlugin.apply]
    B --> C[compiler.hooks.make.tap]
    C --> D[compilation.hooks.processAssets.tapPromise]
    D --> E[createAssets実行]
    E --> F[エントリポイント一覧をイテレート]
    F --> G{entrypoint.nameがapp/で始まるか?}
    G -->|Yes| H[appPathsに追加]
    G -->|No| I[pagesに追加]
    H --> J[EdgeかNodeかを判定]
    I --> J
    J -->|Edge| K[edgeServerPages/edgeServerAppPathsに保存]
    J -->|Node| L[nodeServerPages/nodeServerAppPathsに保存]
    K --> M[マニフェストマージ・出力]
    L --> M
    M --> N{distDirが指定されているか?}
    N -->|Yes| O[fs.writeFileでファイル書き出し]
    N -->|No| P[compilation.emitAssetで出力]
    O --> Q[終了]
    P --> Q
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| エントリ不在 | `getRouteFromEntrypoint`がnullを返した場合 | N/A（スキップ） | エントリポイント設定の確認 |
| 空ファイルエントリ | エントリポイントに.jsファイルが含まれない場合 | N/A（スキップ） | Webpack設定の確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ページ数に依存（数十〜数千ページ） |
| 目標出力時間 | Webpackコンパイル時間内（個別の計測対象外） |
| 同時出力数上限 | 1（ビルドプロセスにつき1ファイル） |

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

pages-manifest.jsonにはサーバー側のファイルパスが含まれるため、`.next/server/` ディレクトリが外部に公開されないように注意が必要。本ファイルはサーバー側でのみ使用され、クライアントには配信されない。

## 備考

- Node.jsサーバーコンパイラとEdgeサーバーコンパイラの両方から呼び出され、モジュールレベル変数（`edgeServerPages`, `nodeServerPages`等）にキャッシュされた後マージされる
- `distDir`が指定されている場合は直接ファイルシステムに書き出し、既存マニフェストとマージする（並列コンパイラ対応）
- `distDir`が未指定の場合はWebpackの`compilation.emitAsset`経由で出力する
- 本番ビルド・Node.jsランタイム時はファイルパスの先頭3文字（`../`相当）がスライスされる

---

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

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

### 推奨読解順序

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

まず、pages-manifest.jsonの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pages-manifest-plugin.ts | `packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts` | `PagesManifest`型（11行目）。シンプルなキー・値（`{ [page: string]: string }`）の型定義 |
| 1-2 | constants.ts | `packages/next/src/shared/lib/constants.ts` | `PAGES_MANIFEST`定数（87行目）、`APP_PATHS_MANIFEST`定数（89行目） |

**読解のコツ**: PagesManifestはシンプルな`Record<string, string>`型であり、キーがルートパス、値がJSファイルパスとなる。

#### Step 2: エントリーポイントを理解する

PagesManifestPluginのWebpackプラグインとしてのライフサイクルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pages-manifest-plugin.ts | `packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts` | プラグインクラス定義（21〜192行目）。`apply`メソッド（181〜191行目）でWebpack hookへの登録を確認 |

**主要処理フロー**:
1. **181行目**: `apply` メソッドで `compiler.hooks.make.tap` によりフック登録
2. **183行目**: `compilation.hooks.processAssets.tapPromise` で非同期処理として登録
3. **188行目**: `createAssets` メソッドが呼び出される

#### Step 3: アセット生成ロジックを理解する

`createAssets` メソッドの内部処理を詳細に追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pages-manifest-plugin.ts | `packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts` | `createAssets`メソッド（46〜178行目）。エントリポイントのイテレーション、ファイルパス抽出、Edge/Nodeの分離、マニフェスト出力 |

**主要処理フロー**:
- **47〜49行目**: エントリポイント取得、pages/appPathsオブジェクト初期化
- **51〜89行目**: エントリポイントをループし、ファイルパスを抽出・分類
- **61〜68行目**: webpack-runtimeファイルの除外フィルタ
- **77〜81行目**: 本番ビルド・Node.jsランタイム時のパススライス処理
- **84〜88行目**: app/で始まるエントリはappPathsに、それ以外はpagesに振り分け
- **93〜99行目**: Edge/Nodeのモジュールレベル変数への保存
- **103〜122行目**: `writeMergedManifest`関数による既存マニフェストとのマージ書き出し
- **124〜150行目**: distDir指定有無による出力方法の分岐

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

```
next build (packages/next/src/cli/next-build.ts)
    |
    +-- Webpack compilation (packages/next/src/build/webpack-config.ts)
            |
            +-- PagesManifestPlugin.apply() [181行目]
                    |
                    +-- compiler.hooks.make.tap
                            |
                            +-- compilation.hooks.processAssets.tapPromise
                                    |
                                    +-- createAssets() [46行目]
                                            |
                                            +-- getRouteFromEntrypoint()
                                            |       (packages/next/src/server/get-route-from-entrypoint.ts)
                                            |
                                            +-- normalizePathSep()
                                            |       (packages/next/src/shared/lib/page-path/normalize-path-sep.ts)
                                            |
                                            +-- writeMergedManifest() [103行目] (distDir指定時)
                                            |       |
                                            |       +-- fs.mkdir / fs.readFile / fs.writeFile
                                            |
                                            +-- compilation.emitAsset() (distDir未指定時)
```

### データフロー図

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

Webpack entrypoints            PagesManifestPlugin.createAssets
  (Node.js compiler) --------> edgeServerPages/nodeServerPages     .next/server/pages-manifest.json
  (Edge compiler) -----------> edgeServerAppPaths/nodeServerAppPaths  .next/server/app-paths-manifest.json
                                    |
                                    +-- マージ処理
                                    +-- writeMergedManifest / emitAsset
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pages-manifest-plugin.ts | `packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts` | ソース | メインのプラグイン実装（PagesManifestPlugin） |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | PAGES_MANIFEST, APP_PATHS_MANIFEST定数定義 |
| get-route-from-entrypoint.ts | `packages/next/src/server/get-route-from-entrypoint.ts` | ソース | エントリポイント名からルートパスへの変換 |
| normalize-path-sep.ts | `packages/next/src/shared/lib/page-path/normalize-path-sep.ts` | ソース | パス区切り文字の正規化 |
| webpack-config.ts | `packages/next/src/build/webpack-config.ts` | ソース | PagesManifestPluginのWebpack設定への組み込み |
| require.ts | `packages/next/src/server/require.ts` | ソース | サーバー側でのpages-manifest読み込み |
| next-server.ts | `packages/next/src/server/next-server.ts` | ソース | サーバーランタイムでのマニフェスト利用 |
| base-server.ts | `packages/next/src/server/base-server.ts` | ソース | ベースサーバーでのマニフェスト参照 |
| filesystem.ts | `packages/next/src/server/lib/router-utils/filesystem.ts` | ソース | ファイルシステムルーティングでの利用 |
| manifest-loader.ts | `packages/next/src/shared/lib/turbopack/manifest-loader.ts` | ソース | Turbopack用のマニフェストローダー |
