# 通知設計書 36-ブロッキングルートエラー通知

## 概要

本ドキュメントは、Next.js開発サーバーにおけるブロッキングルートエラー通知の設計について記載する。Suspense外でのランタイムデータアクセスやナビゲーションブロッキングデータアクセスを検出した場合にオーバーレイで修正方法を案内する通知機能である。

### 本通知の処理概要

ブロッキングルートエラー通知は、App Routerのプリレンダリング最適化において、`<Suspense>`バウンダリ外でランタイムデータ（`cookies()`, `headers()`, `searchParams`）や、ナビゲーションブロッキングデータ（キャッシュされていない`fetch()`、`connection()`等）にアクセスした場合に、開発者に修正方法を案内するオーバーレイを表示する機能である。

**業務上の目的・背景**：Next.jsのApp Routerではページのプリレンダリングとストリーミングを通じて、ユーザーに高速なページロードを提供する。`<Suspense>`外で動的データにアクセスすると、ページ全体のレンダリングがブロックされ、ユーザー体験が低下する。本通知は、このような問題を開発段階で検出し、適切な修正方法（`<Suspense>`の追加や`"use cache"`の使用）を案内することで、パフォーマンスの高いアプリケーション構築を支援する。

**通知の送信タイミング**：ランタイムエラーのメッセージに`/blocking-route`または`/next-prerender-dynamic-viewport`が含まれる場合に検出される。`getBlockingRouteErrorDetails()`関数でエラーメッセージのパターンマッチにより判定される。

**通知の受信者**：開発中のアプリケーションをブラウザで表示している開発者。

**通知内容の概要**：エラー種別ラベル「Blocking Route」、問題の説明（ランタイムデータアクセスまたはナビゲーションブロッキングデータアクセス）、修正方法（`<Suspense>`の追加、`"use cache"`の使用等）、関連ドキュメントリンク（https://nextjs.org/docs/messages/blocking-route）が表示される。`generateViewport()`に関連する場合は専用の説明が表示される。

**期待されるアクション**：開発者は提案された修正方法のいずれかを適用する。具体的には、該当コンポーネントを`<Suspense>`で囲むか、データアクセスを`"use cache"`コンポーネントに移動するか、ランタイムデータアクセスをより深い階層のコンポーネントに移動する。

## 通知種別

ブラウザUI / Dev Overlay（ランタイムエラーオーバーレイの特殊表示）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（ランタイムエラーとして捕捉後、ブロッキングルートエラー判定で特殊表示） |
| 優先度 | 高 |
| リトライ | 無し |

### 送信先決定ロジック

ランタイムエラーオーバーレイの一部として動作する。`getBlockingRouteErrorDetails()`関数がエラーメッセージを解析し、`/blocking-route`または`/next-prerender-dynamic-viewport`パターンに一致する場合に`BlockingRouteErrorDetails`を返す。さらに、`cookies()`の存在により`runtime`（ランタイムデータ）または`navigation`（ナビゲーションブロッキングデータ）のバリアントを判定する。

## 通知テンプレート

### ブラウザUI表示の場合

| 項目 | 内容 |
|-----|------|
| ヘッダーラベル | Blocking Route |
| 問題の説明 | バリアント（runtime/navigation）とリファインメント（generateViewport/空）に応じた説明 |
| 修正方法 | 2つの修正オプション |
| ドキュメントリンク | https://nextjs.org/docs/messages/blocking-route または https://nextjs.org/docs/messages/next-prerender-dynamic-viewport |
| 形式 | HTMLオーバーレイ |

### 本文テンプレート（variant=runtime, refinement=空の場合）

```
[Blocking Route]

Runtime data was accessed outside of <Suspense>

This delays the entire page from rendering, resulting in a slow user experience.
Next.js uses this error to ensure your app loads instantly on every navigation.
cookies(), headers(), and searchParams, are examples of Runtime data that can
only come from a user request.

To fix this:
  Option 1: Provide a fallback UI using <Suspense> around this component.
  Option 2: Move the Runtime data access into a deeper component wrapped in <Suspense>.

Learn more: https://nextjs.org/docs/messages/blocking-route
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| variant | エラーバリアント | 'runtime' or 'navigation'（cookies()の有無で判定） | Yes |
| refinement | リファインメント | '' or 'generateViewport'（エラーメッセージの内容で判定） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ランタイムエラー | Suspense外でのデータアクセス | error.message.includes('/blocking-route') | Suspense外でランタイム/ナビゲーションブロッキングデータにアクセスした場合 |
| ランタイムエラー | generateViewport内でのデータアクセス | error.message.includes('/next-prerender-dynamic-viewport') | generateViewport()内で動的データにアクセスした場合 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| エラーメッセージに該当パターンが含まれない | ブロッキングルートエラーでない場合は通常のランタイムエラー表示 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ランタイムエラー発生] --> B[useErrorDetails呼び出し]
    B --> C[getHydrationErrorDetails - ハイドレーションエラー判定]
    C --> D{ハイドレーションエラー?}
    D -->|Yes| E[ハイドレーションエラー表示]
    D -->|No| F[getBlockingRouteErrorDetails呼び出し]
    F --> G{/blocking-route含む?}
    G -->|Yes| H{cookies()含む?}
    H -->|Yes| I[variant=runtime]
    H -->|No| J[variant=navigation]
    I --> K[BlockingPageLoadErrorDescription表示]
    J --> K
    G -->|No| L{/next-prerender-dynamic-viewport含む?}
    L -->|Yes| M{cookies()含む?}
    M -->|Yes| N[variant=runtime, refinement=generateViewport]
    M -->|No| O[variant=navigation, refinement=generateViewport]
    N --> K
    O --> K
    L -->|No| P[通常のランタイムエラー表示]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| パターン判定失敗 | エラーメッセージのURLパターンが変更された場合 | 通常のランタイムエラーとして表示される（フォールバック） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（開発サーバー稼働中は常時表示可能）

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

- エラーメッセージには開発者向けの技術的な情報のみが含まれ、機密データは含まれない
- Dev Overlayは本番ビルドには含まれない

## 備考

- `BlockingPageLoadErrorDescription`コンポーネントは4つの組み合わせ（variant x refinement）に応じた異なる説明を表示する：
  - variant=runtime, refinement=空：Suspense外でのランタイムデータアクセス
  - variant=navigation, refinement=空：Suspense外でのナビゲーションブロッキングデータアクセス
  - variant=runtime, refinement=generateViewport：generateViewport()内でのランタイムデータアクセス
  - variant=navigation, refinement=generateViewport：generateViewport()内でのナビゲーションブロッキングデータアクセス
- エラー種別ラベルは`getErrorTypeLabel()`で「Blocking Route」に設定される（errors.tsx 440-442行目）

---

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

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

### 推奨読解順序

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

まず、ブロッキングルートエラーの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | errors.tsx | `packages/next/src/next-devtools/dev-overlay/container/errors.tsx` | `BlockingRouteErrorDetails`型（472-476行目）。`type: 'blocking-route'`, `variant: 'navigation' | 'runtime'`, `refinement: '' | 'generateViewport'`の3フィールド |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | errors.tsx | `packages/next/src/next-devtools/dev-overlay/container/errors.tsx` | `getBlockingRouteErrorDetails()`（545-582行目）。3つのパターン（/blocking-route、/next-prerender-dynamic-viewport、/next-prerender-dynamic-metadata除外）の判定ロジック |

**主要処理フロー**:
1. **546行目**: `error.message.includes('/blocking-route')`チェック
2. **549行目**: `cookies()`の有無でvariant判定
3. **558行目**: `/next-prerender-dynamic-metadata`チェック（dynamic-metadataに該当）
4. **569行目**: `/next-prerender-dynamic-viewport`チェック
5. **573行目**: `cookies()`の有無でvariant判定、refinement='generateViewport'

#### Step 3: 表示コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | errors.tsx | `packages/next/src/next-devtools/dev-overlay/container/errors.tsx` | `BlockingPageLoadErrorDescription`コンポーネント（162-433行目）。4つのバリアント x リファインメントの組み合わせに応じた説明を表示 |

**主要処理フロー**:
- **169行目**: `refinement === 'generateViewport'`の場合の分岐
- **260行目**: `refinement === 'generateMetadata'`の場合の分岐（別通知No.37で使用）
- **354行目**: refinement=空、variant=runtimeの場合
- **394行目**: refinement=空、variant=navigationの場合

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

```
Errors [errors.tsx:584]
    |
    +-- useErrorDetails() [errors.tsx:487]
    |      +-- getBlockingRouteErrorDetails() [errors.tsx:545]
    |
    +-- getErrorTypeLabel() [errors.tsx:435]
    |      +-- "Blocking Route" 返却
    |
    +-- BlockingPageLoadErrorDescription [errors.tsx:162]
           +-- variant/refinement に応じた4パターンの説明
```

### データフロー図

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

ランタイムエラー                getBlockingRouteErrorDetails()     ブラウザ
(Error with             ------> variant/refinement判定       ----> オーバーレイ
 /blocking-route)               BlockingPageLoadError              (問題説明 +
                                Description表示                     修正方法 +
                                                                    ドキュメントリンク)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| errors.tsx | `packages/next/src/next-devtools/dev-overlay/container/errors.tsx` | ソース | BlockingRouteErrorDetails型定義、getBlockingRouteErrorDetails判定、BlockingPageLoadErrorDescription表示 |
