# 帳票設計書 39-_devPagesManifest.json

## 概要

本ドキュメントは、Next.js開発サーバー用のページ一覧マニフェスト `_devPagesManifest.json` の設計仕様を定義する。

### 本帳票の処理概要

本帳票は、Next.jsの開発サーバー（`next dev`）においてクライアント側にPages Routerのページ一覧を提供するためのJSONマニフェストである。HMR（Hot Module Replacement）時のページ検出やクライアントサイドナビゲーションに使用される。

**業務上の目的・背景**：本番ビルドではクライアントビルドマニフェスト（`_buildManifest.js`）内の`sortedPages`からページ一覧を取得できるが、開発モードではページが動的に追加・削除されるため、リアルタイムにページ一覧を提供する仕組みが必要である。`_devPagesManifest.json` はHTTPエンドポイントとして開発サーバーから動的に提供され、クライアント側のPageLoaderがページ一覧を取得するために使用する。

**帳票の利用シーン**：(1) 開発モードでのクライアントサイドナビゲーション、(2) ページ追加・削除時のHMR更新通知後のページ一覧再取得、(3) PageLoaderによるルート検出。

**主要な出力内容**：
1. ページパスの配列（`pages`フィールド）

**帳票の出力タイミング**：開発サーバー（`next dev`）の実行中、クライアントからのHTTPリクエスト時に動的に生成される。また、HMRの`DEV_PAGES_MANIFEST_UPDATE`メッセージ受信時にクライアントが再取得する。

**帳票の利用者**：Next.jsクライアントサイドランタイム（PageLoader、page-bootstrap）。

## 帳票種別

開発用マニフェスト（JSON形式のHTTPエンドポイントレスポンス）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | 開発サーバー | `/_next/static/development/_devPagesManifest.json` | クライアントからのfetchリクエスト |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（HTTPレスポンス） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `_devPagesManifest.json` |
| 出力方法 | HTTPレスポンス（Content-Type: application/json） |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

JSONオブジェクトとして以下の構造を持つ。

```json
{
  "pages": [
    "/",
    "/about",
    "/blog/[slug]",
    "/api/hello"
  ]
}
```

### ヘッダー部

N/A

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | pages | Pages Routerのページパス配列 | prevSortedRoutes（App Routerルートを除外） | 文字列配列 | N/A |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 開発モード | `next dev` で実行中であること | Yes |
| Pages Routerルート | App Routerのルート（`appFiles`に含まれるもの）を除外 | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | ルートパス | getSortedRoutes()によるソート順を維持 |

### 改ページ条件

N/A

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

N/A

### 参照テーブル一覧

N/A

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ページ一覧 | prevSortedRoutes.filter(route => !opts.fsChecker.appFiles.has(route)) | N/A | App Routerルートを除外したPages Routerのみ |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[クライアント: PageLoader.getPageList] --> B[fetch: /_next/static/development/_devPagesManifest.json]
    B --> C[開発サーバー: requestHandler]
    C --> D[pathname に clientPagesManifestPath を含む?]
    D -->|Yes| E[prevSortedRoutes からApp Routerルートを除外]
    E --> F[JSON.stringify して pages フィールドに格納]
    F --> G[HTTP 200 レスポンスを返す]
    G --> H[クライアント: window.__DEV_PAGES_MANIFEST に設定]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| fetch失敗 | ネットワークエラー、サーバー未起動 | `Failed to fetch devPagesManifest:` + エラー詳細 | 開発サーバーの起動確認 |
| fetch失敗（クライアント側） | ネットワークブロック | `Failed to fetch _devPagesManifest.json. Is something blocking that network request?` + ドキュメントリンク | ネットワーク設定・プロキシ設定確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数十〜数千ページ |
| 目標出力時間 | 即時（メモリ内データの JSON化のみ） |
| 同時出力数上限 | 複数のブラウザタブからの同時リクエスト対応 |

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

開発モード専用であり、本番環境では出力されない。ページパス一覧が公開されるが、開発環境の localhost アクセスに限定されるため、通常は問題にならない。`credentials: 'same-origin'` でfetchされるため、同一オリジンからのアクセスのみ許可。

## 備考

- 定数名: `DEV_CLIENT_PAGES_MANIFEST`（`packages/next/src/shared/lib/constants.ts` 行101）
- 値: `_devPagesManifest.json`
- 仮想ファイルとして `devVirtualFsItems` に登録され、実ファイルとしては存在しない（HTTPレスポンスとして動的生成）
- HMRメッセージ `DEV_PAGES_MANIFEST_UPDATE` 受信時に `page-bootstrap.ts` がマニフェストを再取得
- `window.__DEV_PAGES_MANIFEST` グローバル変数にキャッシュされ、2回目以降はHTTPリクエストなしで取得
- 本番モードでは `getClientBuildManifest().then(manifest => manifest.sortedPages)` を代わりに使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/next/src/shared/lib/constants.ts` | DEV_CLIENT_PAGES_MANIFEST定数（行101） |
| 1-2 | page-loader.ts | `packages/next/src/client/page-loader.ts` | `__DEV_PAGES_MANIFEST`グローバル変数の型: `{ pages: string[] }`（行25） |

**読解のコツ**: マニフェストの構造はシンプルで、`{ pages: string[] }` の1フィールドのみ。

#### Step 2: サーバー側（提供元）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | setup-dev-bundler.ts | `packages/next/src/server/lib/router-utils/setup-dev-bundler.ts` | requestHandler内のマニフェスト提供ロジック（行1274-1289） |

**主要処理フロー**:
1. **行1265-1266**: clientPagesManifestPathの定義とdevVirtualFsItemsへの登録
2. **行1278-1288**: pathnameがclientPagesManifestPathを含む場合、prevSortedRoutesからApp Routerルートを除外してJSON返却

#### Step 3: クライアント側（消費元）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | page-loader.ts | `packages/next/src/client/page-loader.ts` | getPageList()メソッド（行64-90） |
| 3-2 | page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | DEV_PAGES_MANIFEST_UPDATE HMRハンドラ（行42-53） |

**主要処理フロー**:
- **行64-90（page-loader.ts）**: 開発モードでは`__DEV_PAGES_MANIFEST`をチェック→なければfetchで取得→`__DEV_PAGES_MANIFEST`に設定
- **行42-53（page-bootstrap.ts）**: HMRメッセージ受信時にマニフェストを再取得して`__DEV_PAGES_MANIFEST`を更新

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

```
next dev (開発サーバー)
    │
    ├─ setup-dev-bundler.ts
    │      ├─ clientPagesManifestPath 定義 (行1265)
    │      ├─ devVirtualFsItems.add() (行1266)
    │      └─ requestHandler() (行1274)
    │             └─ JSON.stringify({ pages: filteredRoutes })
    │
    └─ クライアントサイド
           ├─ PageLoader.getPageList() (page-loader.ts 行64)
           │      └─ fetch(_devPagesManifest.json) → window.__DEV_PAGES_MANIFEST
           │
           └─ pageBootstrap() (page-bootstrap.ts 行42)
                  └─ HMR: DEV_PAGES_MANIFEST_UPDATE → 再fetch → 更新
```

### データフロー図

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

prevSortedRoutes ──────────────▶ requestHandler()
opts.fsChecker.appFiles ──────▶     ├─ App Routerルート除外
                                    └─ JSON.stringify()         ──▶ HTTP Response
                                                                    (/_next/static/development/
                                                                     _devPagesManifest.json)
                                                                        │
                                                                        ▼
                                                                    PageLoader.getPageList()
                                                                        │
                                                                        ▼
                                                                    window.__DEV_PAGES_MANIFEST
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| setup-dev-bundler.ts | `packages/next/src/server/lib/router-utils/setup-dev-bundler.ts` | ソース | 開発サーバーでのマニフェスト提供（requestHandler） |
| page-loader.ts | `packages/next/src/client/page-loader.ts` | ソース | クライアント側のページ一覧取得（getPageList） |
| page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | ソース | HMR更新時のマニフェスト再取得 |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | DEV_CLIENT_PAGES_MANIFEST定数 |
