# 通知設計書 18-ビルド完了通知

## 概要

本ドキュメントは、Next.js開発サーバーにおける「ビルド完了通知」（HMR_MESSAGE_SENT_TO_BROWSER.BUILT）の設計を記述する。この通知は、コンパイル完了時にハッシュ、エラー、警告、更新モジュール情報をブラウザへWebSocket経由で送信する。

### 本通知の処理概要

この通知は、コンパイルが完了した際に、コンパイル結果（成功/エラー/警告）をブラウザに通知するHMRメッセージである。SYNCメッセージとは異なり、バージョン情報やDevIndicator情報は含まれない。

**業務上の目的・背景**：開発中のコード変更がコンパイルされた結果を、リアルタイムにブラウザに反映する必要がある。この通知により、コンパイル完了時にエラーがあればエラーオーバーレイを表示し、成功していればHot Module Replacementを適用する。これにより開発者はコード変更の結果を即座に確認できる。

**通知の送信タイミング**：(1) Turbopackモードでは、`project.updateInfoSubscribe`からupdateTypeが`end`のメッセージを受信した場合。(2) Webpackモードでは、クライアントコンパイラまたはサーバーコンパイラのdoneフックが発火した場合。

**通知の受信者**：WebSocket接続を確立しているすべてのブラウザクライアント。Turbopackモードではクライアントごとのエラー情報を含む。

**通知内容の概要**：コンパイルハッシュ、エラー配列、警告配列、更新モジュール一覧が含まれる。

**期待されるアクション**：エラーがあればエラーオーバーレイを表示する。警告があればコンソールに出力する。正常完了の場合はHMRを適用する（Webpackモードではmodule.hot.check/apply、Turbopackモードではreportのみ）。

## 通知種別

WebSocket（アプリ内通知） - ブラウザへのHMRメッセージ

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（WebSocket push） |
| 優先度 | 高 |
| リトライ | 無 |

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

Turbopackモードでは`sendToClient`関数でクライアントごとに個別送信され、各クライアントのclientIssuesも含まれる。Webpackモードでは`WebpackHotMiddleware.publishStats()`を通じて全クライアントに同一メッセージが送信される。

## 通知テンプレート

### メール通知の場合

該当なし

### 本文テンプレート

```json
{
  "type": "built",
  "hash": "{コンパイルハッシュ}",
  "errors": [],
  "warnings": [],
  "updatedModules": ["module1", "module2"]
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージタイプ識別子 | HMR_MESSAGE_SENT_TO_BROWSER.BUILT定数 (`built`) | Yes |
| hash | コンパイルハッシュ値 | Turbopack: hmrHashカウンタ、Webpack: stats.hash | Yes |
| errors | コンパイルエラー配列 | currentTopLevelIssues + currentEntryIssues + clientIssues | Yes |
| warnings | コンパイル警告配列 | stats.warnings（Webpackモード）または空配列 | Yes |
| updatedModules | 更新モジュール一覧 | Webpack stats.updatedModules（オプション） | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コンパイル完了 | Turbopack updateInfoSubscribe `end`イベント | 常に送信 | hot-reloader-turbopack.ts 1484-1537行目 |
| コンパイル完了 | Webpack clientコンパイラdoneフック | closed状態でなく、サーバーエラーがない | hot-middleware.ts onClientDone（113-117行目） |
| コンパイル完了 | Webpack serverコンパイラdoneフック | エラーがある場合のみ | hot-middleware.ts onServerDone（127-133行目） |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| closed状態 | WebpackHotMiddlewareがclose()された場合 |
| Webpackサーバーエラーなし時のサーバーdone | サーバーコンパイラにエラーがない場合、onServerDoneではBUILTを送信しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[コンパイル完了] --> B{バンドラー種別}
    B -->|Turbopack| C[updateInfoSubscribe end受信]
    C --> D[sendEnqueuedMessages実行]
    D --> E[クライアントごとのエラー収集]
    E --> F[各クライアントにsendToClientでBUILTメッセージ送信]
    B -->|Webpack| G[doneフック発火]
    G --> H[stats.toJsonで統計情報取得]
    H --> I[publishStatsでBUILTメッセージ送信]
    F --> J[クライアント側処理]
    I --> J
    J --> K{エラーあり?}
    K -->|Yes| L[エラーオーバーレイ表示]
    K -->|No| M[HMR適用]
```

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

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| コンパイルエラー | ソースコードにシンタックスエラー等 | errors配列にエラー情報を含めて送信、クライアントでオーバーレイ表示 |
| HMR適用失敗 | モジュール更新の適用に失敗 | フルリロードにフォールバック |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

開発サーバー稼働中は常時送信可能

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

- 開発環境専用
- エラーメッセージにはファイルパスやソースコードの断片が含まれうる

## 備考

- Turbopackモードでは、BUILTメッセージ送信後にhmrEventHappenedフラグがtrueの場合、コンパイル時間をコンソールに「Compiled in Xs」として出力する（hot-reloader-turbopack.ts 1539-1545行目）
- クライアント側ではBUILTとSYNCは同じcaseブロックで処理されるが、BUILTの場合のみhandleHotUpdate()が呼び出される（hot-reloader-app.tsx 370-372行目）
- Webpackモードでは、statsのtoJsonでhash, errors, warningsのみを抽出する（hot-middleware.ts 215-221行目）
- TurbopackモードではクライアントごとにclientIssuesが異なるため、個別にBUILTメッセージを構築して送信する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 87-93行目: BuiltMessage型定義。hash, errors, warnings, updatedModulesフィールド |
| 1-2 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 28行目: BUILT = `built` |

#### Step 2: サーバー側送信ロジック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | 1484-1537行目: handleProjectUpdates内のupdateType `end`処理。クライアントごとのエラー収集とBUILTメッセージ送信 |
| 2-2 | hot-middleware.ts | `packages/next/src/server/dev/hot-middleware.ts` | 214-229行目: publishStats関数。stats.toJsonで情報を抽出しBUILTメッセージをpublish |

**主要処理フロー（Turbopack）**:
1. **1484行目**: updateType `end`を検出
2. **1485行目**: sendEnqueuedMessages()でキュー内メッセージを先に送信
3. **1515-1517行目**: currentTopLevelIssuesとcurrentEntryIssuesからエラーを収集
4. **1519-1537行目**: 各クライアントのclientIssuesを加えてBUILTメッセージを個別送信

#### Step 3: クライアント側受信処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 298-374行目: BUILT/SYNCの共通処理。BUILTの場合のみhandleHotUpdate()が呼ばれる |
| 3-2 | hot-reloader-pages.ts | `packages/next/src/client/dev/hot-reloader/pages/hot-reloader-pages.ts` | 293-341行目: Pages RouterでのBUILT/SYNC処理 |

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

```
[サーバー側 - Turbopack]
hot-reloader-turbopack.ts: handleProjectUpdates()
    |
    +-- updateType === 'end'
            |
            +-- sendEnqueuedMessages()
            +-- エラー収集(topLevel + entry + client)
            +-- for each client:
                    sendToClient(client, { type: BUILT, hash, errors, warnings })

[サーバー側 - Webpack]
hot-middleware.ts: WebpackHotMiddleware
    |
    +-- compilers[0].hooks.done.tap(onClientDone)
            |
            +-- publishStats(statsResult)
                    +-- stats.toJson({ hash, warnings, errors })
                    +-- publish({ type: BUILT, hash, warnings, errors })

[クライアント側]
processMessage()
    |
    +-- case BUILT:
            +-- dispatcher.buildingIndicatorHide()
            +-- handleAvailableHash(hash)
            +-- [エラーあり] handleErrors(errors)
            +-- [警告あり] 警告コンソール出力
            +-- [正常] sendMessage({ event: 'client-success' })
            +-- handleHotUpdate()
                    +-- [Turbopack] turbopackHmr.onBuilt() + reportHmrLatency
                    +-- [Webpack] tryApplyUpdatesWebpack()
```

### データフロー図

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

コンパイル完了          サーバー側                          ブラウザ
                  ----> エラー/警告/ハッシュ収集
                        |
                        v
                  BuiltMessage生成
                  { type: "built",
                    hash, errors, warnings }
                        |
                        v
                  WebSocket JSON送信 ----------> processMessage()
                                                 |
                                                 v
                                          handleHotUpdate()
                                          -> HMR適用 or エラー表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | ソース | BuiltMessage型定義 |
| hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | ソース | Turbopackモード送信ロジック |
| hot-middleware.ts | `packages/next/src/server/dev/hot-middleware.ts` | ソース | Webpackモード送信ロジック |
| hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | ソース | App Routerクライアント側処理 |
| hot-reloader-pages.ts | `packages/next/src/client/dev/hot-reloader/pages/hot-reloader-pages.ts` | ソース | Pages Routerクライアント側処理 |
| turbopack-hot-reloader-common.ts | `packages/next/src/client/dev/hot-reloader/turbopack-hot-reloader-common.ts` | ソース | TurbopackHmr.onBuilt()メソッド |
