# 通知設計書 28-Fast Refreshフルリロード通知

## 概要

本ドキュメントは、Next.js開発サーバーにおけるFast Refreshフルリロード通知の設計を記述する。Fast Refreshがランタイムエラーによりフルリロードを実行する場合にコンソールへ警告メッセージを表示し、開発者にフルリロードの理由を伝達する仕組みについて定義する。

### 本通知の処理概要

Fast Refresh（Hot Module Replacement）の適用中にランタイムエラーが発生した場合、ページのフルリロードが必要となる。この際、コンソール（サーバー側およびブラウザ側）に警告メッセージを表示し、開発者にフルリロードの原因を通知する。

**業務上の目的・背景**：Fast Refreshは通常、ページのフルリロードなしにコード変更を反映する。しかし、ランタイムエラーが発生した場合やモジュールの依存関係が複雑な場合はフルリロードが必要となる。開発者がフルリロードの発生理由を理解し、コードの改善（Fast Refresh対応のモジュール構造への変更）を行えるようにするため、明確な警告メッセージを提供する。

**通知の送信タイミング**：(1) サーバー側：クライアントから`client-full-reload`イベントを受信し、`hadRuntimeError`フラグが`true`の場合。(2) ブラウザ側：HMR更新適用中にランタイムエラーが検出された場合（`RuntimeErrorHandler.hadRuntimeError`が`true`）。

**通知の受信者**：(1) サーバー側：開発者のターミナル（コンソール出力）。(2) ブラウザ側：開発者のブラウザコンソール。

**通知内容の概要**：定数文字列 `"Fast Refresh had to perform a full reload due to a runtime error."`。サーバー側では追加で依存チェーン情報（`dependencyChain`）がある場合、変更されたモジュールパスとドキュメントリンクも表示される。

**期待されるアクション**：開発者はフルリロードの原因となったランタイムエラーを調査し、Fast Refreshが正常に動作するようコードを修正する。

## 通知種別

コンソールメッセージ（ターミナル出力 + ブラウザコンソール）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コンソール出力） |
| 優先度 | 中 |
| リトライ | なし |

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

サーバー側：クライアントからの`client-full-reload`イベントの`hadRuntimeError`フラグに基づいて`Log.warn()`で出力。ブラウザ側：`RuntimeErrorHandler.hadRuntimeError`の状態に基づいて`console.warn()`で出力。

## 通知テンプレート

### メール通知の場合

該当なし（コンソールメッセージのため）

### 本文テンプレート

```
Fast Refresh had to perform a full reload due to a runtime error.
```

サーバー側追加メッセージ（依存チェーンがある場合）：
```
Fast Refresh had to perform a full reload when {modulePath} changed. Read more: https://nextjs.org/docs/messages/fast-refresh-reload
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| FAST_REFRESH_RUNTIME_RELOAD | 基本メッセージ定数 | `messages.ts`の定数 | Yes |
| modulePath | 変更されたモジュールパス | `dependencyChain[0]`から取得・整形 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| クライアントイベント | `client-full-reload`受信（サーバー側） | `hadRuntimeError === true` | クライアントからのフルリロード報告 |
| クライアントイベント | HMR更新適用エラー（ブラウザ側） | `RuntimeErrorHandler.hadRuntimeError === true` | ブラウザ側でのHMR適用失敗 |
| クライアントイベント | SERVER_COMPONENT_CHANGES受信（ブラウザ側） | `RuntimeErrorHandler.hadRuntimeError === true` | Server Component変更時にランタイムエラーあり |
| クライアントイベント | TURBOPACK_MESSAGE受信（ブラウザ側） | `RuntimeErrorHandler.hadRuntimeError === true` | Turbopack更新時にランタイムエラーあり |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `hadRuntimeError`がfalse | ランタイムエラーなしの場合はメッセージ非表示 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[HMR更新受信] --> B{ランタイムエラーあり?}
    B -->|Yes| C[console.warn FAST_REFRESH_RUNTIME_RELOAD]
    B -->|No| D[通常のHMR更新適用]
    C --> E[performFullReload実行]
    E --> F[client-full-reloadイベントをサーバーへ送信]
    F --> G{hadRuntimeError?}
    G -->|Yes| H[サーバー: Log.warn FAST_REFRESH_RUNTIME_RELOAD]
    G -->|No| I[ログ出力なし]
    H --> J{dependencyChainあり?}
    J -->|Yes| K[モジュールパス付き警告メッセージ出力]
    J -->|No| L[基本メッセージのみ]
```

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

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| フルリロード失敗 | `window.location.reload()`が失敗 | ブラウザ依存の動作（通常は再試行不要） |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

本通知はローカル開発環境専用のコンソールメッセージであり、機密情報は含まれない。モジュールパス情報が表示されるが、開発環境のみで使用されるためリスクは低い。

## 備考

- `FAST_REFRESH_RUNTIME_RELOAD`定数は`packages/next/src/server/dev/messages.ts`で定義されている。
- ブラウザ側では`REACT_REFRESH_FULL_RELOAD`と`REACT_REFRESH_FULL_RELOAD_FROM_ERROR`の2種類のメッセージが使い分けられる（前者はHMR適用失敗、後者はランタイムエラーによるフルリロード）。
- サーバー側のモジュールパス整形では`[project]`プレフィックスの除去と`[...]`/`(...)`サフィックスの除去が行われる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | messages.ts | `packages/next/src/server/dev/messages.ts` | 7-8行目: `FAST_REFRESH_RUNTIME_RELOAD`定数の定義。固定文字列 |

#### Step 2: サーバー側のログ出力を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | 990-1006行目: `client-full-reload`イベント処理。`hadRuntimeError`フラグ判定と`Log.warn(FAST_REFRESH_RUNTIME_RELOAD)`出力。`dependencyChain`がある場合のモジュールパス付きメッセージ |

**主要処理フロー**:
1. **990行目**: `client-full-reload`イベントの処理開始
2. **991行目**: `hadRuntimeError`と`dependencyChain`を取得
3. **992-993行目**: `hadRuntimeError`が`true`なら`Log.warn(FAST_REFRESH_RUNTIME_RELOAD)`
4. **995-1005行目**: `dependencyChain`がある場合、モジュールパスを整形して追加の警告メッセージ出力

#### Step 3: ブラウザ側のコンソール出力を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 116-138行目: `performFullReload`関数。スタックトレース情報をサーバーに送信後フルリロード |
| 3-2 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 153-161行目: `handleApplyUpdates`内でランタイムエラー時に`REACT_REFRESH_FULL_RELOAD`を`console.warn` |
| 3-3 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 391-394行目: `TURBOPACK_MESSAGE`受信時にランタイムエラーがある場合の`REACT_REFRESH_FULL_RELOAD_FROM_ERROR`と`performFullReload` |

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

```
[ブラウザ側]
processMessage(TURBOPACK_MESSAGE/SERVER_COMPONENT_CHANGES/BUILT) [hot-reloader-app.tsx]
    |
    +-- RuntimeErrorHandler.hadRuntimeError チェック
           |
           +-- [true] console.warn(REACT_REFRESH_FULL_RELOAD_FROM_ERROR)
           +-- [true] performFullReload(err, sendMessage) [hot-reloader-app.tsx:116]
                  |
                  +-- sendMessage({ event: 'client-full-reload', hadRuntimeError, ... })
                  +-- window.location.reload()

[サーバー側]
client.addEventListener('message') [hot-reloader-turbopack.ts:955]
    |
    +-- case 'client-full-reload': [hot-reloader-turbopack.ts:990]
           |
           +-- [hadRuntimeError] Log.warn(FAST_REFRESH_RUNTIME_RELOAD) [hot-reloader-turbopack.ts:993]
           +-- [dependencyChain] Log.warn('Fast Refresh had to perform a full reload when {module} changed.')
```

### データフロー図

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

HMR更新メッセージ          ──> ランタイムエラー検出              ──> コンソール警告メッセージ
RuntimeErrorHandler            performFullReload()                  console.warn (ブラウザ)
  .hadRuntimeError             client-full-reloadイベント送信       Log.warn (サーバー)
                                                                      |
                                                                      v
                                                                 window.location.reload()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| messages.ts | `packages/next/src/server/dev/messages.ts` | ソース | FAST_REFRESH_RUNTIME_RELOAD定数定義 |
| hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | ソース | サーバー側client-full-reloadイベント処理 |
| hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | ソース | ブラウザ側performFullReload、HMR更新処理 |
| page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | ソース | Pages RouterクライアントでのperformFullReload |
| runtime-error-handler.ts | `packages/next/src/client/dev/runtime-error-handler.ts` | ソース | RuntimeErrorHandler状態管理 |
| shared.ts | `packages/next/src/client/dev/hot-reloader/shared.ts` | ソース | REACT_REFRESH_FULL_RELOAD定数定義 |
