# 機能設計書 38-Partial Prerendering（PPR）

## 概要

本ドキュメントは、Next.jsにおけるPartial Prerendering（PPR）機能の設計を記述する。PPRは静的シェルと動的コンテンツを組み合わせたハイブリッドレンダリング方式であり、ビルド時に静的部分を事前生成しつつ、リクエスト時に動的部分をストリーミングで埋め込む実験的機能である。

### 本機能の処理概要

**業務上の目的・背景**：従来のレンダリング方式では、ページ全体が静的（SSG）または動的（SSR）のいずれかに分類される必要があった。PPRはページ内の静的部分と動的部分を自動的に分離し、静的シェルをCDNからの即座配信しつつ、動的コンテンツをストリーミングで補完する。これによりCDNキャッシュの恩恵と動的コンテンツの両立を実現する。

**機能の利用シーン**：ECサイトの商品ページ（静的な商品情報 + 動的な在庫/価格情報）、ダッシュボード（静的なレイアウト + 動的なデータ）、パーソナライズを含むページ（静的なUI + 動的なユーザー情報）で利用される。

**主要な処理内容**：
1. ビルド時の静的シェル（HTMLの骨格）の事前生成
2. `experimental_ppr`設定によるPPR有効化の判定
3. Suspenseバウンダリを使用した静的/動的部分の分離
4. リクエスト時の動的コンテンツのストリーミング生成
5. `checkIsAppPPREnabled`と`checkIsRoutePPREnabled`による細粒度制御

**関連システム・外部連携**：App Router、React Suspense、Staged Rendering（No.39）、Resume Data Cache（No.40）。

**権限による制御**：権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | PPRは画面固有ではなく、レンダリングインフラとして機能する |

## 機能種別

レンダリング処理 / キャッシュ最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| config | ExperimentalPPRConfig | No | PPR設定値（boolean \| 'incremental' \| undefined） | boolean、'incremental'、またはundefined |

### 入力データソース

- `next.config.js`の`experimental.ppr`設定
- ルートセグメント設定の`experimental_ppr`エクスポート

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 静的シェルHTML | string | ビルド時に生成される静的HTMLの骨格 |
| 動的ストリーム | ReadableStream | リクエスト時に生成される動的コンテンツ |

### 出力先

- CDNキャッシュ（静的シェル）
- HTTPストリーミングレスポンス（動的コンテンツ）

## 処理フロー

### 処理シーケンス

```
1. ビルド時
   └─ checkIsAppPPREnabledでアプリ全体のPPR有効化を確認
   └─ 各ルートに対してcheckIsRoutePPREnabledを確認
   └─ 静的シェルの生成（Suspenseバウンダリのfallback部分）
2. リクエスト時
   └─ CDNから静的シェルを即座に配信
   └─ 動的部分のストリーミングレンダリングを開始
   └─ Suspenseバウンダリのfallbackを実コンテンツで置換
3. クライアント側
   └─ 静的シェルを即座に表示
   └─ 動的コンテンツの到着に応じてUIを更新
```

### フローチャート

```mermaid
flowchart TD
    A[next build] --> B{PPR有効?}
    B -->|No| C[通常ビルド]
    B -->|Yes| D[静的シェル生成]
    D --> E[Suspenseバウンダリ検出]
    E --> F[静的部分をHTMLに事前生成]
    F --> G[CDNにキャッシュ]

    H[リクエスト受信] --> I[CDNから静的シェル配信]
    I --> J[動的部分のストリーミング開始]
    J --> K[Suspense Fallback置換]
    K --> L[レスポンス完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | アプリレベル有効化 | configがboolean trueまたは'incremental'の場合にPPRが有効 | next.config.jsのexperimental.ppr |
| BR-38-02 | ルートレベル有効化 | configがboolean trueの場合にのみルートでPPRが有効（'incremental'はルートレベルでは無効） | ルートセグメント設定 |
| BR-38-03 | incremental モード | 'incremental'設定時はexperimental_ppr = trueをエクスポートしたページのみPPRが有効 | config === 'incremental' |
| BR-38-04 | App Router専用 | PPRはApp Routerでのみ利用可能 | App Routerのルート |

### 計算ロジック

PPR有効判定:
```
checkIsAppPPREnabled: config === true || config === 'incremental'
checkIsRoutePPREnabled: config === true (incrementalの場合はfalse)
```

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 設定エラー | PPR設定値が無効な場合 | boolean、'incremental'、またはundefinedを指定する |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- 静的シェルのCDN配信によりTTFBを最小化
- 動的部分のストリーミングによりFCPを最適化
- Suspenseバウンダリの適切な配置によりレンダリング効率を最大化

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

- 静的シェルはCDNに公開キャッシュされるため、ユーザー固有の情報を含めないこと
- 動的部分はリクエストごとに生成されるため、認証情報等のセンシティブデータはここで処理する

## 備考

- PPRは実験的機能（experimental）であり、APIが変更される可能性がある
- PPRの動作はStaged Rendering（No.39）とResume Data Cache（No.40）と密接に連携する
- `experimental.ppr: 'incremental'`を使用すると、ページごとにPPRの有効/無効を制御できる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ppr.ts | `packages/next/src/server/lib/experimental/ppr.ts` | ExperimentalPPRConfig型とチェック関数を確認する |

**読解のコツ**: **9行目**に`ExperimentalPPRConfig = boolean | 'incremental'`が定義されている。この型がPPR設定の全パターンを網羅する。

#### Step 2: アプリレベルの有効化判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ppr.ts | `packages/next/src/server/lib/experimental/ppr.ts` | checkIsAppPPREnabled関数を確認する |

**主要処理フロー**:
1. **18-32行目**: `checkIsAppPPREnabled` - undefinedならfalse、booleanならそのまま、'incremental'ならtrue

#### Step 3: ルートレベルの有効化判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ppr.ts | `packages/next/src/server/lib/experimental/ppr.ts` | checkIsRoutePPREnabled関数を確認する |

**主要処理フロー**:
- **42-52行目**: `checkIsRoutePPREnabled` - undefinedならfalse、booleanならそのまま、'incremental'ではfalse（ルートレベルではexperimental_pprエクスポートが必要）

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

```
next.config.js (experimental.ppr)
    │
    ├─ checkIsAppPPREnabled(config)
    │      └─ アプリ全体のPPR有効判定
    │
    └─ checkIsRoutePPREnabled(config)
           └─ ルート単位のPPR有効判定
                  │
                  ├─ [ビルド時] 静的シェル生成
                  │      └─ Suspenseバウンダリの検出と分離
                  │
                  └─ [リクエスト時] 動的レンダリング
                         └─ StagedRenderingController
                         └─ ResumeDataCache
```

### データフロー図

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

PPR設定 ─────────▶ checkIsAppPPREnabled() ──▶ 有効/無効判定
                                                    │
ルート設定 ──────▶ checkIsRoutePPREnabled() ─▶ ルート判定
                                                    │
React要素ツリー ─▶ [ビルド時] ──────────────▶ 静的シェルHTML
                                                    │
リクエスト ──────▶ [リクエスト時] ─────────▶ 動的ストリーム
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ppr.ts | `packages/next/src/server/lib/experimental/ppr.ts` | ソース | PPR設定チェック関数 |
| staged-rendering.ts | `packages/next/src/server/app-render/staged-rendering.ts` | ソース | 段階的レンダリング制御（PPRと連携） |
| resume-data-cache.ts | `packages/next/src/server/resume-data-cache/resume-data-cache.ts` | ソース | データキャッシュ（PPRと連携） |
