# 通知設計書 13-ミドルウェア変更通知

## 概要

本ドキュメントは、Next.js開発サーバーにおける「ミドルウェア変更通知」（HMR_MESSAGE_SENT_TO_BROWSER.MIDDLEWARE_CHANGES）の設計を記述する。この通知は、ミドルウェアファイルの変更を検出した際にブラウザへWebSocket経由で通知し、ページのフルリロードをトリガーする。

### 本通知の処理概要

この通知は、Next.jsのミドルウェア（`middleware.ts`/`middleware.js`）に変更が検出された際に、開発サーバーからブラウザへHMRメッセージとして送信される仕組みである。

**業務上の目的・背景**：Next.jsのミドルウェアはリクエスト処理パイプラインの最上流で実行され、ルーティング、リダイレクト、ヘッダー操作などの横断的関心事を処理する。ミドルウェアの変更はすべてのルートに影響するため、部分的なHMRでは不十分であり、ページの完全リロードが必要となる。この通知により、ミドルウェア変更時にブラウザが自動的にフルリロードを実行し、開発者は最新のミドルウェアロジックで動作を確認できる。

**通知の送信タイミング**：ミドルウェアファイル（`middleware.ts`/`middleware.js`）に変更が検出され、Turbopackのchangeサブスクリプションが変更を通知した場合。

**通知の受信者**：WebSocket接続を確立しているすべてのブラウザクライアント。

**通知内容の概要**：メッセージタイプ`middlewareChanges`のみが含まれるシンプルなメッセージ（追加データなし）。

**期待されるアクション**：ブラウザはメッセージ受信後、`window.location.reload()`を呼び出してページの完全リロードを実行する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

Turbopackモードでは`sendHmr`関数を通じて全クライアントのメッセージキューに追加される。Webpackモードではon-demand-entry-handler内の同等のロジックで送信される。

## 通知テンプレート

### メール通知の場合

該当なし

### 本文テンプレート

```json
{
  "type": "middlewareChanges"
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージタイプ識別子 | HMR_MESSAGE_SENT_TO_BROWSER.MIDDLEWARE_CHANGES定数 (`middlewareChanges`) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル変更 | middleware.ts/middleware.jsの変更検出 | Turbopackのchangeサブスクリプションで変更が通知された場合 | turbopack-utils.tsのhandleEntrypoints内でミドルウェアエンドポイントのサブスクリプションが登録される |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| WebSocket未接続 | ブラウザがWebSocket接続を確立していない場合 |
| コンパイルエラー中 | sendEnqueuedMessagesのエラーチェックにより送信が保留される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[middleware.tsファイル変更検出] --> B[Turbopack changeサブスクリプション通知]
    B --> C[MiddlewareChangesMessage生成]
    C --> D[sendHmr経由で全クライアントのキューに追加]
    D --> E[sendEnqueuedMessagesでJSON送信]
    E --> F[クライアント側でwindow.location.reload実行]
```

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

### 参照テーブル一覧

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| WebSocket送信失敗 | クライアント接続切断 | 送信スキップ |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- 開発環境専用の通知であり、本番環境には含まれない
- メッセージには機密情報は含まれない

## 備考

- MiddlewareChangesMessageは最もシンプルなHMRメッセージの一つで、typeフィールドのみを持つ
- App RouterのprocessMessage（hot-reloader-app.tsx 537行目）ではMIDDLEWARE_CHANGESの処理を`page-bootstrap.ts`に委譲している
- Pages Routerでも同様にpage-bootstrap.tsで処理される（55-57行目）
- page-bootstrap.tsでは`window.location.reload()`を直接呼び出す

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 115-117行目: MiddlewareChangesMessage型定義。typeフィールドのみの最小構造 |
| 1-2 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 24行目: MIDDLEWARE_CHANGES = `middlewareChanges` |

#### Step 2: エントリーポイントを理解する（サーバー側）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | turbopack-utils.ts | `packages/next/src/server/dev/turbopack-utils.ts` | handleEntrypoints関数内でミドルウェアのchangeサブスクリプションが登録される |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | 55-57行目: MIDDLEWARE_CHANGESメッセージ受信時にwindow.location.reload()を呼び出す |
| 3-2 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 537-541行目: App RouterではMIDDLEWARE_CHANGESをpage-bootstrap.tsに委譲 |

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

```
[サーバー側]
turbopack-utils.ts: handleEntrypoints()
    |
    +-- ミドルウェアendpointのchangeサブスクリプション
            |
            +-- createMessage() -> { type: MIDDLEWARE_CHANGES }
                    |
                    +-- sendHmr()
                            +-- sendEnqueuedMessages() -> WebSocket送信

[クライアント側]
page-bootstrap.ts: addMessageListener()
    |
    +-- case MIDDLEWARE_CHANGES:
            +-- window.location.reload()
```

### データフロー図

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

middleware.ts変更   ----> Turbopack検出
                         |
                         v
                   MiddlewareChangesMessage生成
                   { type: "middlewareChanges" }
                         |
                         v
                   WebSocket JSON送信 ----------> page-bootstrap.ts
                                                  |
                                                  v
                                           window.location.reload()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | ソース | MiddlewareChangesMessage型定義 |
| turbopack-utils.ts | `packages/next/src/server/dev/turbopack-utils.ts` | ソース | ミドルウェアサブスクリプション登録 |
| hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | ソース | WebSocket送信インフラ |
| page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | ソース | クライアント側のMIDDLEWARE_CHANGES処理（フルリロード実行） |
| 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側のメッセージルーティング |
