# 機能設計書 77-オブジェクトシリアライゼーション

## 概要

本ドキュメントは、webpackのSerializer / ObjectMiddleware / FileMiddleware / BinaryMiddlewareによるコンパイル結果のシリアライズ・デシリアライズ機能について、その処理パイプライン・データ形式・ミドルウェアアーキテクチャを詳細に記述した機能設計書である。

### 本機能の処理概要

オブジェクトシリアライゼーション機能は、webpackのコンパイル結果（モジュール、チャンク、依存関係等の複雑なオブジェクトグラフ）をバイナリ形式にシリアライズし、ファイルシステムに永続化することでキャッシュ機能を実現する。

**業務上の目的・背景**：大規模プロジェクトではwebpackのフルビルドに数十秒から数分を要する。ファイルシステムキャッシュを実現するためには、コンパイル結果の複雑なオブジェクトグラフ（循環参照を含む）を効率的にシリアライズ/デシリアライズする仕組みが必要である。本機能により、2回目以降のビルドでキャッシュからの復元が可能となり、ビルド時間を大幅に短縮できる。

**機能の利用シーン**：cache.type: "filesystem"設定時のコンパイル結果の永続化。リビルド時のキャッシュからの復元。開発サーバーでの高速リビルド。

**主要な処理内容**：
1. Serializerクラスによるミドルウェアパイプラインの管理
2. ObjectMiddlewareによるJavaScriptオブジェクトグラフの中間表現への変換（循環参照対応、型登録ベース）
3. BinaryMiddlewareによる中間表現のバイナリエンコーディング（数値圧縮、文字列最適化）
4. FileMiddlewareによるバイナリデータのファイルシステムへの読み書き（圧縮対応）

**関連システム・外部連携**：ファイルシステム（IntermediateFileSystem）。gzip/brotli圧縮ライブラリ。各オブジェクトクラスのserialize/deserializeメソッド。

**権限による制御**：本機能に権限による制御はない。

## 関連画面

本機能に直接関連する画面はない。キャッシュの永続化はバックグラウンドで行われる。

## 機能種別

データ永続化・シリアライゼーション処理

## 入力仕様

### 入力パラメータ

Serializer:

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| middlewares | SerializerMiddleware[] | Yes | シリアライズミドルウェアの配列 | 少なくとも1つ必要 |
| context | Context | No | コンテキストオブジェクト | - |

### 入力データソース

- コンパイル結果のオブジェクトグラフ（Module、Chunk、Dependency等のインスタンス）
- ファイルシステムキャッシュファイル（デシリアライズ時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (シリアライズ) | Buffer | バイナリ形式のシリアライズ済みデータ |
| (デシリアライズ) | Object | 復元されたオブジェクトグラフ |

### 出力先

シリアライズ: ファイルシステムのキャッシュディレクトリ。デシリアライズ: メモリ上のオブジェクトグラフ。

## 処理フロー

### 処理シーケンス

```
シリアライズ:
1. Serializer.serialize(obj, context)
   ├─ ObjectMiddleware.serialize(obj, context)
   │   ├─ オブジェクトグラフの走査
   │   ├─ 型登録に基づくシリアライザ選択
   │   ├─ 循環参照の検出と参照ID割り当て
   │   └─ 中間表現（ESCAPEシーケンスベース）の生成
   ├─ BinaryMiddleware.serialize(data, context)
   │   ├─ 型別のバイナリエンコーディング
   │   │   ├─ null → NullsSection（連続nullの圧縮）
   │   │   ├─ boolean → BooleansSection
   │   │   ├─ number → F64/I32/I8NumbersSection
   │   │   ├─ string → ShortString/StringSection
   │   │   ├─ Buffer → BufferSection
   │   │   └─ BigInt → BigIntSection
   │   └─ セクション化されたバイナリデータ生成
   └─ FileMiddleware.serialize(data, context)
       ├─ ヘッダ生成（Version + SectionCount + SectionSizes）
       ├─ 圧縮（gzip/brotli、設定による）
       └─ ファイルシステムへの書き込み

デシリアライズ（逆順）:
1. Serializer.deserialize(value, context)
   ├─ FileMiddleware.deserialize → バイナリ読み込み・解凍
   ├─ BinaryMiddleware.deserialize → 中間表現への変換
   └─ ObjectMiddleware.deserialize → オブジェクト復元
```

### フローチャート

```mermaid
flowchart TD
    A[オブジェクトグラフ] --> B[ObjectMiddleware]
    B --> C[中間表現]
    C --> D[BinaryMiddleware]
    D --> E[バイナリデータ]
    E --> F[FileMiddleware]
    F --> G[圧縮+ファイル書き込み]

    H[ファイル読み込み+解凍] --> I[FileMiddleware]
    I --> J[バイナリデータ]
    J --> K[BinaryMiddleware]
    K --> L[中間表現]
    L --> M[ObjectMiddleware]
    M --> N[オブジェクトグラフ復元]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-77-01 | 型登録ベースシリアライズ | makeSerializableで登録されたクラスのみシリアライズ可能 | ObjectMiddleware |
| BR-77-02 | 循環参照対応 | 循環参照はrelativeOffset（負の整数）として参照IDで表現 | ObjectMiddleware |
| BR-77-03 | 遅延デシリアライズ | LazyFunction/writeSeparateにより部分的な遅延デシリアライズが可能 | ObjectMiddleware |
| BR-77-04 | null圧縮 | 連続するnull値はNullsSectionとして圧縮される | BinaryMiddleware |
| BR-77-05 | ファイル形式 | ヘッダ（Version + SectionCount + SectionSizes）+ Section*のフォーマット | FileMiddleware |
| BR-77-06 | バージョンチェック | ファイルのVERSION（0x01637077 = "wpc" + 1）が一致しない場合はデシリアライズ失敗 | FileMiddleware |
| BR-77-07 | 圧縮対応 | gzipまたはbrotliによる圧縮/解凍をサポート | FileMiddleware |
| BR-77-08 | ハッシュベースファイル名 | シリアライズデータのハッシュに基づくファイル名で遅延セクションを分割保存 | FileMiddleware |

### 計算ロジック

BinaryMiddlewareのエンコーディング形式:
- ShortString: 0b1nnn_nnnn (n:length) + ASCII bytes（127バイト以下の文字列）
- F64Numbers: 0b001n_nnnn (n:count-1) + f64*
- I32Numbers: 0b010n_nnnn (n:count-1) + i32*
- I8Numbers: 0b011n_nnnn (n:count-1) + i8*
- Nulls: 0b0001_nnnn (n:count-1)

## データベース操作仕様

本機能にデータベース操作はない。ファイルシステムをストレージとして使用する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | 未登録クラスのシリアライズ試行 | makeSerializableでクラスを登録 |
| - | Error | VERSIONミスマッチ | キャッシュをクリアして再ビルド |
| - | Error | ファイル読み込み/書き込みエラー | ファイルシステムの権限・容量を確認 |

### リトライ仕様

リトライは行わない。キャッシュ破損時はキャッシュクリアで対処する。

## トランザクション仕様

FileMiddlewareは書き込み完了までの一貫性を保証する。部分的な書き込み失敗時はキャッシュファイルが不完全になる可能性があり、次回ビルドで検出・再生成される。

## パフォーマンス要件

- 書き込みサイズ制限: WRITE_LIMIT_TOTAL = 0x7fff0000、WRITE_LIMIT_CHUNK = 511 * 1024 * 1024
- 圧縮チャンクサイズ: COMPRESSION_CHUNK_SIZE = 100MB
- 数値の型別最適化（I8/I32/F64）によりバイナリサイズを最小化
- 連続null値の圧縮によりオーバーヘッドを削減

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

キャッシュファイルにはソースコード情報が含まれる可能性がある。キャッシュディレクトリへのアクセス制御が必要。

## 備考

- ミドルウェアパイプラインの順序はシリアライズ時は順方向、デシリアライズ時は逆方向で処理される
- 各ミドルウェアはSerializerMiddleware抽象クラスを継承する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SerializerMiddleware.js | `lib/serialization/SerializerMiddleware.js` | ミドルウェア抽象基底クラス。serialize/deserializeの抽象メソッド、LazyFunction型 |
| 1-2 | types.js | `lib/serialization/types.js` | シリアライズ可能な型の定義 |

**読解のコツ**: SerializerMiddlewareはテンプレートメソッドパターンで、各具象ミドルウェアがserialize/deserializeを実装する。LazyFunctionは遅延評価のための特殊な関数型。

#### Step 2: パイプラインマネージャ

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Serializer.js | `lib/serialization/Serializer.js` | ミドルウェアパイプラインの管理。シリアライズ時は順方向、デシリアライズ時は逆方向 |

**主要処理フロー**:
- **22-26行目**: コンストラクタ。middlewares順方向/逆方向の配列保持
- **34-57行目**: serializeメソッド。各ミドルウェアのserializeを連鎖実行
- **65-79行目**: deserializeメソッド。各ミドルウェアのdeserializeを逆順で連鎖実行

#### Step 3: オブジェクト→中間表現変換

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ObjectMiddleware.js | `lib/serialization/ObjectMiddleware.js` | オブジェクトグラフの中間表現変換。型登録、循環参照、ESCAPEシーケンス |

**主要処理フロー**:
- **28-48行目**: シリアライズデータフォーマットの説明コメント
- **50-70行目**: ObjectSerializerContext/ObjectDeserializerContext型定義
- **89-110行目**: setSetSize/setMapSize/toHashヘルパー

#### Step 4: バイナリエンコーディング

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BinaryMiddleware.js | `lib/serialization/BinaryMiddleware.js` | 各データ型のバイナリエンコーディング形式 |

**読解のコツ**: 先頭のコメントにバイナリフォーマットの詳細な仕様が記載されている（13-75行目）。ヘッダバイトのビットパターンで型を識別する。

#### Step 5: ファイルI/O

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | FileMiddleware.js | `lib/serialization/FileMiddleware.js` | ファイルフォーマット、圧縮、ハッシュベースファイル名 |

**主要処理フロー**:
- **29-43行目**: ファイルフォーマットの仕様コメント（Header + Section*）
- **46行目**: VERSION定数（0x01637077）
- **47-48行目**: WRITE_LIMIT定数

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

```
PackFileCacheStrategy
    |
    +-- new Serializer([ObjectMiddleware, BinaryMiddleware, FileMiddleware])
            |
            +-- serialize(compilationData, context)
            |       +-- ObjectMiddleware.serialize() → 中間表現
            |       +-- BinaryMiddleware.serialize() → バイナリ
            |       +-- FileMiddleware.serialize() → ファイル
            |
            +-- deserialize(filePath, context)
                    +-- FileMiddleware.deserialize() → バイナリ
                    +-- BinaryMiddleware.deserialize() → 中間表現
                    +-- ObjectMiddleware.deserialize() → オブジェクト
```

### データフロー図

```
[シリアライズ]

Object Graph ──> ObjectMiddleware ──> 中間表現 ──> BinaryMiddleware ──> バイナリ ──> FileMiddleware ──> .pack file
  (Module,         (型ID,参照ID,      (ESCAPEシーケンス)    (セクション化      (ヘッダ+圧縮
   Chunk,           循環参照解決)                            バイナリ)         +ファイル書き込み)
   Dependency)

[デシリアライズ]

.pack file ──> FileMiddleware ──> バイナリ ──> BinaryMiddleware ──> 中間表現 ──> ObjectMiddleware ──> Object Graph
  (読み込み      (解凍)          (デコード)     (セクション解析)    (型復元,
   +ヘッダ解析)                                                   参照解決)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Serializer.js | `lib/serialization/Serializer.js` | ソース | ミドルウェアパイプラインマネージャ |
| SerializerMiddleware.js | `lib/serialization/SerializerMiddleware.js` | ソース | ミドルウェア抽象基底クラス |
| ObjectMiddleware.js | `lib/serialization/ObjectMiddleware.js` | ソース | オブジェクト→中間表現変換 |
| BinaryMiddleware.js | `lib/serialization/BinaryMiddleware.js` | ソース | 中間表現→バイナリ変換 |
| FileMiddleware.js | `lib/serialization/FileMiddleware.js` | ソース | バイナリ→ファイルI/O |
| SingleItemMiddleware.js | `lib/serialization/SingleItemMiddleware.js` | ソース | 単一アイテム用ミドルウェア |
| types.js | `lib/serialization/types.js` | ソース | シリアライズ可能な型定義 |
| PlainObjectSerializer.js | `lib/serialization/PlainObjectSerializer.js` | ソース | プレーンオブジェクトのシリアライザ |
| MapObjectSerializer.js | `lib/serialization/MapObjectSerializer.js` | ソース | Mapオブジェクトのシリアライザ |
| SetObjectSerializer.js | `lib/serialization/SetObjectSerializer.js` | ソース | Setオブジェクトのシリアライザ |
| ArraySerializer.js | `lib/serialization/ArraySerializer.js` | ソース | 配列のシリアライザ |
| makeSerializable.js | `lib/util/makeSerializable.js` | ソース | クラスのシリアライズ登録ユーティリティ |
