# 帳票設計書 6-prerender-manifest.json

## 概要

本ドキュメントは、Next.jsビルドプロセスにおいて生成される `prerender-manifest.json` の設計を記述する。このマニフェストは、ISR（Incremental Static Regeneration）およびSSG（Static Site Generation）で事前レンダリングされるルートとその再検証・有効期限設定を定義する。

### 本帳票の処理概要

prerender-manifest.json は、ビルドプロセスの静的生成フェーズで構築される `PrerenderManifest` オブジェクトを `writePrerenderManifest` 関数でJSON出力するファイルである。各ルートの再検証間隔（revalidate）、有効期限（expire）、フォールバック設定、PPR（Partial Prerendering）設定等を管理し、Next.jsサーバーが適切なキャッシュ戦略を実行するための基盤情報を提供する。

**業務上の目的・背景**：Next.jsのISR/SSGでは、ビルド時に事前レンダリングされたページを配信し、一定間隔で再生成する。この再検証間隔やフォールバック動作をルートごとに管理する必要がある。prerender-manifest.jsonは、サーバーが各ルートの配信戦略（静的キャッシュの寿命、オンデマンド再生成の要否、フォールバックHTMLの有無等）を判断するための情報を一元管理する。

**帳票の利用シーン**：本番サーバーでのリクエスト処理時にキャッシュ戦略を決定する際、ISR対象ページの再検証タイミングを管理する際、動的ルートのフォールバック動作を制御する際、デプロイメントプラットフォームでのキャッシュ設定に使用される。

**主要な出力内容**：
1. `routes` - 事前レンダリング済みルートとその再検証設定のマッピング
2. `dynamicRoutes` - 動的ルートのフォールバック設定・正規表現パターン
3. `notFoundRoutes` - 404を返すルートのリスト
4. `preview` - プレビューモード用の認証情報（previewModeId等）
5. `version` - マニフェストバージョン（現在4）

**帳票の出力タイミング**：`next build` コマンド実行時、静的生成フェーズの完了後に `writePrerenderManifest` 関数で出力される。

**帳票の利用者**：Next.jsサーバーランタイム（ISR/SSGキャッシュ管理）、デプロイメントプラットフォーム（CDNキャッシュ設定）、`_ssgManifest.js`生成処理（クライアント側SSGページ一覧）。

## 帳票種別

ビルドマニフェスト（JSON形式のISR/SSGキャッシュ設定ファイル）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | `next build` | ビルドコマンド実行 |

## 出力形式

### 基本仕様

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

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

prerender-manifest.json は、ルート情報と動的ルート設定を含むJSONオブジェクトである。

```
{
  "version": 4,
  "routes": {
    "/": {
      "initialRevalidateSeconds": 60,
      "initialExpireSeconds": 300,
      "srcRoute": "/",
      "dataRoute": "/.rsc",
      "initialStatus": 200,
      "initialHeaders": {},
      "renderingMode": "PARTIALLY_STATIC",
      "experimentalPPR": true,
      "allowHeader": [...]
    }
  },
  "dynamicRoutes": {
    "/blog/[slug]": {
      "routeRegex": "...",
      "dataRoute": "/blog/[slug].rsc",
      "fallback": "/blog/[slug].html",
      "fallbackRevalidate": 60,
      "experimentalPPR": false,
      "renderingMode": "STATIC"
    }
  },
  "notFoundRoutes": [],
  "preview": {
    "previewModeId": "...",
    "previewModeSigningKey": "...",
    "previewModeEncryptionKey": "..."
  }
}
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | version | マニフェストバージョン | 固定値 `4` | 数値 |
| 2 | preview | プレビューモード認証情報 | `previewProps` オブジェクト | オブジェクト |

### 明細部（routes）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | initialRevalidateSeconds | 再検証間隔（秒） | `cacheControl.revalidate` | 数値/false | N/A |
| 2 | initialExpireSeconds | 有効期限（秒） | `cacheControl.expire` | 数値/undefined | N/A |
| 3 | srcRoute | 元のルートパス | `page` 変数 | 文字列 | N/A |
| 4 | dataRoute | データルートパス | `${normalizedRoute}${RSC_SUFFIX}` | 文字列/null | N/A |
| 5 | prefetchDataRoute | プリフェッチデータルート | PPR有効時のdataRoute | 文字列/undefined | N/A |
| 6 | initialStatus | 初期ステータスコード | 404ルートは404、それ以外はmeta.status | 数値 | N/A |
| 7 | initialHeaders | 初期ヘッダー | `collectMeta(metadata)` | オブジェクト | N/A |
| 8 | renderingMode | レンダリングモード | PPR設定に基づく（PARTIALLY_STATIC/STATIC） | 文字列/undefined | N/A |
| 9 | experimentalPPR | PPR実験的フラグ | `isRoutePPREnabled` | 真偽値 | N/A |
| 10 | experimentalBypassFor | バイパス条件 | `bypassFor` | 配列/undefined | N/A |
| 11 | allowHeader | 許可ヘッダー | `ALLOWED_HEADERS` 定数 | 配列 | N/A |

### 明細部（dynamicRoutes）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | routeRegex | ルート正規表現 | `getNamedRouteRegex()` | 文字列 | N/A |
| 2 | dataRoute | データルートパス | RSCサフィックス付きパス | 文字列/null | N/A |
| 3 | fallback | フォールバック設定 | `fallbackModeToFallbackField()` | 文字列/false/null | N/A |
| 4 | fallbackRevalidate | フォールバック再検証間隔 | PPR時の`cacheControl.revalidate` | 数値/undefined | N/A |
| 5 | fallbackExpire | フォールバック有効期限 | PPR時の`cacheControl.expire` | 数値/undefined | N/A |
| 6 | fallbackStatus | フォールバックステータス | `meta.status` | 数値/undefined | N/A |
| 7 | fallbackHeaders | フォールバックヘッダー | `meta.headers` | オブジェクト/undefined | N/A |
| 8 | renderingMode | レンダリングモード | PPR設定に基づく | 文字列/undefined | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | notFoundRoutes | 404を返すルート一覧 | 静的生成結果 | 文字列配列 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| SSG/ISRページ | `getStaticProps` または App Router の静的ルートが存在 | Yes |
| 静的生成完了 | 静的生成フェーズが完了していること | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | routes/dynamicRoutes（sortPagesObject使用） | ソート済み |

### 改ページ条件

N/A

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

N/A

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

N/A

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| dataRoute | `path.posix.join(normalizedRoute + RSC_SUFFIX)` | N/A | App RouteHandlerの場合はnull |
| fallback | `fallbackModeToFallbackField(fallbackMode, pathname)` | N/A | PRERENDER/BLOCKING_STATIC_RENDER/NOT_FOUND等 |
| routeRegex | `normalizeRouteRegex(getNamedRouteRegex(pathname).re.source)` | N/A | 動的ルートの正規表現パターン |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[next build実行] --> B[静的生成フェーズ開始]
    B --> C[prerenderManifest初期化 version:4]
    C --> D[各ページの静的解析・生成]
    D --> E{ページ種別判定}
    E -->|静的SSG/ISR| F[routes に追加]
    E -->|動的ルート| G[dynamicRoutes に追加]
    E -->|404ページ| H[notFoundRoutes に追加]
    F --> I[再検証・有効期限設定]
    G --> J[フォールバック・正規表現設定]
    H --> K[writePrerenderManifest実行]
    I --> K
    J --> K
    K --> L[routes/dynamicRoutesをソート]
    L --> M[.next/prerender-manifest.jsonに出力]
    M --> N[writeClientSsgManifest実行]
    N --> O[_ssgManifest.js出力]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 静的生成失敗 | ページの静的生成中にエラーが発生 | ビルドエラーとして報告 | ページのgetStaticProps/generateStaticParams修正 |
| revalidate値不正 | revalidate値が数値でもfalseでもない場合 | バリデーションエラー | next.config.jsまたはページコード修正 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | SSG/ISRルート数 + 動的ルート数（数十〜数万ルート） |
| 目標出力時間 | マニフェスト書き出し自体は数ミリ秒（静的生成は別途） |
| 同時出力数上限 | 1 |

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

prerender-manifest.jsonの`preview`フィールドにはプレビューモードの認証情報（previewModeId、previewModeSigningKey、previewModeEncryptionKey）が含まれる。これらはセッションに使用される秘密情報であるため、`.next/` ディレクトリの外部非公開が必須。

## 備考

- version 4 が現在のマニフェストバージョン
- `writePrerenderManifest` は出力前に `sortPagesObject` でroutes/dynamicRoutesをソートする
- 出力後に `writeClientSsgManifest` が呼ばれ、クライアント向け `_ssgManifest.js` が生成される
- PPR有効時は `renderingMode` に `PARTIALLY_STATIC` が設定される
- `initialRevalidateSeconds: false` はISRが無効（永続キャッシュ）を意味する
- i18n設定がある場合、ロケール別のルートも `routes` に追加される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | constants.ts | `packages/next/src/shared/lib/constants.ts` | `PRERENDER_MANIFEST`定数（97行目） |
| 1-2 | index.ts | `packages/next/src/build/index.ts` | `PrerenderManifest`型（importで参照）。routes/dynamicRoutes/notFoundRoutes/preview/versionの構造 |

**読解のコツ**: PrerenderManifestは複雑な型を持ち、routes内の各エントリには多数のフィールドがある。PPR関連のフィールドはexperimentalプレフィックスが付く。

#### Step 2: 初期化と構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/next/src/build/index.ts` | 2874〜2880行目。PrerenderManifestの初期化 |
| 2-2 | index.ts | `packages/next/src/build/index.ts` | 3357〜3373行目。静的ルートのroutes追加処理 |
| 2-3 | index.ts | `packages/next/src/build/index.ts` | 3545〜3570行目。動的ルートのdynamicRoutes追加処理 |

**主要処理フロー**:
1. **2874行目**: `prerenderManifest` オブジェクト初期化（version: 4, 空のroutes/dynamicRoutes/notFoundRoutes, previewProps）
2. **3357〜3373行目**: 静的ルートごとにrevalidate/expire/status/headers/PPR設定等を設定
3. **3545〜3570行目**: 動的ルートごとにrouteRegex/fallback/PPR設定等を設定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/next/src/build/index.ts` | 548〜555行目。`writePrerenderManifest`関数。sortPagesObjectでソート後、writeManifestで出力 |
| 3-2 | index.ts | `packages/next/src/build/index.ts` | 557〜589行目。`writeClientSsgManifest`関数。クライアント向けSSGマニフェスト生成 |

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

```
next build (build/index.ts)
    |
    +-- 静的生成フェーズ
    |       |
    |       +-- prerenderManifest初期化 [2874行目]
    |       |
    |       +-- routes構築 [3357行目]
    |       |
    |       +-- dynamicRoutes構築 [3545行目]
    |       |
    |       +-- notFoundRoutes構築 [3176行目]
    |
    +-- writePrerenderManifest() [548行目]
    |       |
    |       +-- sortPagesObject() [553〜554行目]
    |       |
    |       +-- writeManifest() [555行目]
    |               → .next/prerender-manifest.json
    |
    +-- writeClientSsgManifest() [557行目]
            |
            +-- devalue(ssgPages) [581行目]
                    → .next/static/{buildId}/_ssgManifest.js
```

### データフロー図

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

getStaticProps結果 -----------------> prerenderManifest.routes構築
generateStaticParams結果 -----------> prerenderManifest.dynamicRoutes構築
next.config.js (preview設定) -------> prerenderManifest.preview
                                          |
                                          +-- sortPagesObject
                                          +-- writeManifest -----------> .next/prerender-manifest.json
                                          |
prerenderManifest.routes -----------> writeClientSsgManifest ---------> .next/static/{buildId}/_ssgManifest.js
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/next/src/build/index.ts` | ソース | PrerenderManifest構築・出力（writePrerenderManifest/writeClientSsgManifest） |
| constants.ts | `packages/next/src/shared/lib/constants.ts` | ソース | PRERENDER_MANIFEST定数 |
| base-server.ts | `packages/next/src/server/base-server.ts` | ソース | サーバーランタイムでのマニフェスト読み込み・ISR制御 |
| next-server.ts | `packages/next/src/server/next-server.ts` | ソース | 本番サーバーでのキャッシュ戦略決定 |
