# 通知設計書 24-CSSリロード通知

## 概要

本ドキュメントは、Bun DevServerにおけるCSSファイル変更時のホットリロード通知機能の設計を定義する。この通知により、CSSファイルの変更がブラウザにリアルタイムで反映され、ページ全体のリロードなしにスタイル更新が可能となる。

### 本通知の処理概要

この通知は、CSSファイルが変更された際に、DevServerからHMRクライアントへ新しいCSSコンテンツを送信し、ブラウザ上でスタイルシートを動的に更新するホットリロード機能である。

**業務上の目的・背景**：フロントエンド開発において、スタイルの調整は頻繁に行われる作業である。従来のページリロードでは、ページの状態（フォーム入力、スクロール位置、モーダルの開閉状態など）が失われ、開発効率が低下する。CSSホットリロードにより、ページ状態を維持したままスタイルのみを更新でき、開発者の反復作業の効率が大幅に向上する。また、CSSの変更は比較的安全（副作用が少ない）であるため、JavaScriptのHMRよりも信頼性が高い。

**通知の送信タイミング**：以下のイベント発生時に送信される：
1. CSSファイルが変更されたとき（ファイル監視で検知）
2. CSSファイルをインポートしているファイルが再バンドルされたとき
3. ルートのCSSリストが変更されたとき（インポートの追加/削除）

**通知の受信者**：`hot_update`トピックにサブスクライブしているHMRクライアント（ブラウザ）。特に、変更されたCSSに関連するルートを表示しているクライアントが主な対象。

**通知内容の概要**：hot_updateメッセージの一部として、以下の情報が含まれる：
1. 各ルートのCSSファイルリスト（配列更新用）
2. 変更されたCSSファイルの新しいコンテンツ

**期待されるアクション**：HMRクライアントは受信したデータを処理し、`editCssArray`でルートのCSSリストを更新、`editCssContent`で個々のCSSファイルの内容を更新する。CSSStyleSheetオブジェクトを使用して、既存の`<link>`タグを無効化しつつ新しいスタイルを適用する。

## 通知種別

WebSocket通知（HMR hot_updateメッセージの一部）

## 送信仕様

### 基本情報

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

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

hot_updateメッセージは`HmrTopic.hot_update`トピックにサブスクライブしているすべてのクライアントに送信される。クライアント側で現在のルートインデックス（`currentRouteIndex`）に基づいてフィルタリングが行われ、関連するCSSのみが適用される。

## 通知テンプレート

### メッセージフォーマット

| 項目 | 内容 |
|-----|------|
| プロトコル | WebSocket |
| 形式 | バイナリ（hot_updateメッセージに埋め込み） |
| エンコーディング | Little-endian、UTF-8 |

### 本文テンプレート（hot_updateメッセージ内のCSS関連部分）

```
MessageId.hot_update ('u')
├─ [List 1] サーバーサイド更新ルート (i32配列、-1で終端)
├─ [List 2] ルートごとのCSSリスト
│   └─ 各ルート:
│       ├─ ルートバンドルID (i32) - -1で終端
│       ├─ CSS数 (i32) - -1の場合CSS変更なし
│       └─ 各CSS:
│           └─ CSS識別子 (16バイト ASCII hex)
├─ [List 3] CSS内容更新
│   ├─ 更新数 (u32)
│   └─ 各更新:
│       ├─ CSS識別子 (16バイト ASCII hex)
│       ├─ コンテンツ長 (u32)
│       └─ CSSコンテンツ (UTF-8)
└─ [残り] JavaScriptモジュール更新
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| route_bundle_id | ルートバンドルのインデックス | RouteBundle.Index | Yes |
| css_identifier | CSSファイルの16文字hex識別子 | アセットハッシュ | Yes |
| css_content | CSSファイルの内容 | バンドル結果 | Yes |
| css_count | ルートに関連するCSS数 | IncrementalGraph | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル変更 | CSSファイルの保存 | バンドル成功 | ファイル監視で検知 |
| インポート変更 | CSS importの追加/削除 | バンドル成功 | 依存関係グラフの更新 |
| ルート変更 | ルートファイルの更新 | バンドル成功 | ルートに関連するCSSリストの再計算 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| バンドル失敗 | CSSパースエラー等でバンドルが失敗した場合、errorsメッセージが代わりに送信される |
| CSS変更なし | CSSの内容が変更されていない場合、List 3は空になる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ファイル変更検知] --> B[バンドル実行]
    B --> C{バンドル成功?}
    C -->|No| D[errorsメッセージ送信]
    C -->|Yes| E[hot_updateペイロード生成]
    E --> F[List 1: サーバーサイド更新ルート]
    F --> G[List 2: 各ルートのCSSリスト]
    G --> H[List 3: 変更されたCSSコンテンツ]
    H --> I[JavaScriptモジュール追加]
    I --> J[publish hot_update]
    D --> K[終了]
    J --> K
```

### クライアント側処理フロー

```mermaid
flowchart TD
    A[hot_updateメッセージ受信] --> B[currentRouteIndexを確認]
    B --> C[List 2をパース]
    C --> D{該当ルートあり?}
    D -->|No| E[スキップ]
    D -->|Yes| F[editCssArray呼び出し]
    F --> G[List 3をパース]
    G --> H[各CSSに対してeditCssContent呼び出し]
    H --> I[CSSStyleSheet更新]
    I --> J[link要素を無効化]
    E --> K[終了]
    J --> K
```

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

### 参照テーブル一覧

本通知はデータベースを使用しない。すべてのデータはメモリ上のDevServer構造から取得される。

| 構造体名 | 用途 | 備考 |
|---------|------|------|
| IncrementalGraph | CSS依存関係の追跡 | client_graph |
| RouteBundle | ルートごとのCSS情報 | route_bundles |
| Assets | CSSコンテンツの保存 | assets |

### 更新テーブル一覧

なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| CSSパースエラー | 不正なCSS構文 | errorsメッセージで通知、オーバーレイ表示 |
| ファイル読み込みエラー | ファイルアクセス失敗 | バンドル失敗として処理 |
| WebSocket切断 | クライアント切断 | 再接続後に状態を再同期 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（開発環境でのみ使用）

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

- この機能は開発環境専用であり、本番環境では使用されない
- CSSコンテンツには機密情報を含めるべきではない
- CSSインジェクション攻撃のリスクは低い（開発環境のためソース管理下）

## 備考

- CSSホットリロードは、フレームワークがSSRで`<link>`要素を生成することを前提としている
- クライアントサイドルーティング時は、MutationObserverで`<head>`への`<link>`追加を監視
- 同一CSSファイルの複数回更新は、最新のスタイルのみが適用される
- `document.adoptedStyleSheets`を使用して動的にスタイルを適用

---

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

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

### 推奨読解順序

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

CSSリロードで使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | css-reloader.ts | `src/bake/client/css-reloader.ts` | CSS構造体（sheet, link, active）、cssStoreマップ（行18-25） |
| 1-2 | hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | MessageId.hot_updateハンドラ（行118-196）、CSS処理部分（行138-168） |

**読解のコツ**: TypeScriptのInterfaceとMapの使い方に注目。cssStoreはCSSファイルの状態を管理する中心的なデータ構造。

#### Step 2: クライアント側のCSS更新処理を理解する

ブラウザ側でCSSがどのように更新されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | css-reloader.ts | `src/bake/client/css-reloader.ts` | editCssArray関数（行146-169） |
| 2-2 | css-reloader.ts | `src/bake/client/css-reloader.ts` | editCssContent関数（行171-187） |
| 2-3 | css-reloader.ts | `src/bake/client/css-reloader.ts` | activateCss/deactivateCss関数（行33-56） |

**主要処理フロー**:
1. **行146-162**: editCssArrayで現在のCSSリストを更新し、削除されたCSSを無効化
2. **行171-177**: editCssContentでCSSStyleSheetを作成または更新
3. **行178**: document.adoptedStyleSheetsに追加して適用
4. **行181-182**: 元のlink要素のスタイルシートを無効化

#### Step 3: MutationObserverによるDOM監視を理解する

フレームワークによる`<link>`タグの追加/削除を監視する仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | css-reloader.ts | `src/bake/client/css-reloader.ts` | headObserver MutationObserver（行59-107） |
| 3-2 | css-reloader.ts | `src/bake/client/css-reloader.ts` | maybeAddCssLink関数（行109-135） |

**主要処理フロー**:
- **行59-107**: childListとattributes（disabled）の変更を監視
- **行109-135**: `/_bun/asset/`で始まるhrefを持つlinkを検出してcssStoreに登録

#### Step 4: サーバー側のCSS処理を理解する

DevServer側でCSSがどのようにバンドルされ送信されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | DevServer.zig | `src/bake/DevServer.zig` | finalizeBundle関数のCSS処理部分 |
| 4-2 | DevServer.zig | `src/bake/DevServer.zig` | MessageId.hot_updateの定義とコメント（行3784-3821） |

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

```
[サーバー側]
DevServer (ファイル変更検知)
    │
    └─ バンドル実行
           │
           └─ finalizeBundle()
                  │
                  ├─ List 1: サーバーサイド更新ルート生成
                  ├─ List 2: 各ルートのCSSリスト生成
                  ├─ List 3: CSSコンテンツ生成
                  └─ publish(.hot_update, payload)

[クライアント側]
WebSocket.onmessage()
    │
    └─ handlers[MessageId.hot_update]() [hmr-runtime-client.ts:118]
           │
           ├─ DataViewReader でパース
           │
           ├─ [List 2処理]
           │      │
           │      └─ editCssArray() [css-reloader.ts:146]
           │             │
           │             ├─ activateCss() - 既存CSSを有効化
           │             └─ deactivateCss() - 削除されたCSSを無効化
           │
           └─ [List 3処理]
                  │
                  └─ editCssContent() [css-reloader.ts:171]
                         │
                         ├─ new CSSStyleSheet() - 初回
                         ├─ sheet.replace(newContent) - 更新
                         └─ document.adoptedStyleSheets.push()
```

### データフロー図

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

CSSファイル変更            DevServer                      WebSocket
      │              ───▶  バンドル実行            ───▶   hot_update
      │                         │                         メッセージ
      ▼                         ▼
ファイル監視               CSS依存関係
(bun_watcher)              グラフ更新
                                │
                                ▼
                           ペイロード生成
                           (List 2, List 3)

[クライアント側]

hot_update          css-reloader.ts                    ブラウザ
メッセージ    ───▶  editCssArray()              ───▶   スタイル適用
      │             editCssContent()
      ▼                   │
DataViewReader            ▼
パース              CSSStyleSheet
                    更新/作成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| css-reloader.ts | `src/bake/client/css-reloader.ts` | ソース | クライアント側CSS更新ロジック |
| hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | ソース | HMRクライアントエントリポイント、hot_updateハンドラ |
| DevServer.zig | `src/bake/DevServer.zig` | ソース | サーバー側バンドル・配信ロジック |
| data-view.ts | `src/bake/client/data-view.ts` | ソース | バイナリメッセージのパースヘルパー |
