# 機能設計書 71-マニフェスト生成

## 概要

本ドキュメントは、webpackのManifestPluginによるビルド成果物のマニフェストファイル生成機能について、その処理内容・入出力仕様・ビジネスルールを詳細に記述した機能設計書である。

### 本機能の処理概要

ManifestPluginは、webpackのビルドプロセスで生成されたアセット情報を収集し、エントリポイントとアセットのマッピング情報をJSON形式のマニフェストファイルとして出力する機能である。

**業務上の目的・背景**：モダンなWebアプリケーションでは、ビルド時にファイル名にハッシュが付与されるためキャッシュバスティングが実現できるが、サーバーサイドからアセットの実際のファイル名を知る手段が必要となる。マニフェストファイルは、論理的なアセット名と実際のファイルパスの対応表を提供し、サーバーサイドレンダリングやHTMLテンプレートからの参照を可能にする。

**機能の利用シーン**：サーバーサイドレンダリング（SSR）環境でHTMLを生成する際に、ビルド済みアセットのパスをマニフェストから取得する場合。CDN配信時にアセットの正確なURLを特定する場合。デプロイ自動化ツールがビルド成果物の一覧を取得する場合。

**主要な処理内容**：
1. コンパイル完了後のアセット処理フェーズ（PROCESS_ASSETS_STAGE_SUMMARIZE）でマニフェスト生成を実行
2. エントリポイント情報の収集（チャンク名、ファイル名、親エントリポイント）
3. 全チャンクのファイルおよび補助ファイルの収集（HotUpdateChunkを除外）
4. アセット名の正規化（ハッシュ除去、ソースファイル名の使用）
5. オプションのfilter関数によるアセットのフィルタリング
6. オプションのgenerate関数によるマニフェストオブジェクトの変換
7. JSON形式でのマニフェストファイルの出力

**関連システム・外部連携**：webpack-sourcesライブラリ（RawSource）を使用してアセットデータを生成する。schema-utilsライブラリを使用してオプションのバリデーションを行う。

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

## 関連画面

本機能に直接関連する画面はない。ビルドツールとしてのバックエンド機能である。

## 機能種別

データ生成処理（マニフェストファイル出力）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filename | string | No | 出力マニフェストファイル名 | デフォルト: "manifest.json" |
| prefix | string | No | アセットパスの接頭辞 | デフォルト: "[publicpath]"。[publicpath]プレースホルダーが使用可能 |
| entrypoints | boolean | No | エントリポイント情報を含めるか | デフォルト: true |
| filter | function | No | アセットフィルタリング関数 | ManifestItemを受け取りbooleanを返す |
| generate | function | No | マニフェスト変換関数 | ManifestObjectを受け取りManifestObjectを返す |
| serialize | function | No | シリアライズ関数 | デフォルト: JSON.stringify(manifest, null, 2) |

### 入力データソース

- Compilationオブジェクト: エントリポイント情報、チャンク情報、アセット情報
- 出力設定: publicPath、hashDigestLength

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| entrypoints | object | エントリポイント名をキーとし、imports配列とオプションのparents配列を値とするオブジェクト |
| assets | object | アセット名をキーとし、file（パス付きファイル名）とオプションのsrc（ソースファイル名）を値とするオブジェクト |

### 出力先

ビルド出力ディレクトリ内のマニフェストファイル（デフォルト: manifest.json）。compilation.emitAssetを通じてアセットとして出力される。

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   └─ オプションのバリデーションとデフォルト値の設定
2. コンパイルフックへの登録
   └─ thisCompilation -> processAssets (PROCESS_ASSETS_STAGE_SUMMARIZE)
3. マニフェストオブジェクトの構築
   ├─ 3a. エントリポイント情報の収集（entrypoints=trueの場合）
   │   └─ 各エントリポイントのチャンクからファイル名を収集
   ├─ 3b. チャンクアセットの収集
   │   ├─ HotUpdateChunkを除外
   │   ├─ 補助ファイルの処理
   │   └─ メインファイルの処理（チャンク名 + 拡張子）
   └─ 3c. 全アセットの処理
       └─ HMRアセットを除外
4. フィルタリング（filter関数が指定されている場合）
5. マニフェスト変換（generate関数が指定されている場合）
6. シリアライズしてアセットとして出力
```

### フローチャート

```mermaid
flowchart TD
    A[processAssetsフック発火] --> B{entrypoints有効?}
    B -->|Yes| C[エントリポイント情報を収集]
    B -->|No| D[チャンクのイテレーション開始]
    C --> D
    D --> E{HotUpdateChunk?}
    E -->|Yes| F[スキップ]
    E -->|No| G[補助ファイルを処理]
    G --> H[メインファイルを処理]
    H --> I{次のチャンク?}
    I -->|Yes| D
    I -->|No| J[残りのアセットを処理]
    J --> K{filter指定?}
    K -->|Yes| L[フィルタリング適用]
    K -->|No| M{generate指定?}
    L --> M
    M -->|Yes| N[マニフェスト変換]
    M -->|No| O[シリアライズして出力]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | ハッシュ除去 | アセット名からhashDigestLengthに基づくハッシュパターンを除去する | hashDigestLength > 0の場合 |
| BR-71-02 | HotUpdateChunk除外 | HotUpdateChunkに属するファイルはマニフェストに含めない | 常時 |
| BR-71-03 | HMRアセット除外 | hotModuleReplacementフラグが付いたアセットはマニフェストに含めない | 常時 |
| BR-71-04 | 重複排除 | 同一ファイルは一度だけマニフェストに追加される | 常時 |
| BR-71-05 | publicPath解決 | prefix内の[publicpath]プレースホルダーをpublicPathで置換する。publicPathが"auto"の場合は"/"を使用 | 常時 |
| BR-71-06 | チャンク名優先 | アセット名にはチャンク名を優先使用し、名前がない場合はチャンクIDを使用 | 常時 |
| BR-71-07 | 拡張子判定 | gz、br、map拡張子は二重拡張子として扱い、その前の拡張子も含めて返す | 常時 |

### 計算ロジック

特になし。

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

本機能にデータベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | ManifestPluginOptionsがスキーマに適合しない場合 | schema-utilsによるバリデーションエラーメッセージを確認し、オプションを修正 |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。マニフェスト生成はcompilation.emitAssetにより原子的に行われる。

## パフォーマンス要件

全チャンクと全アセットのイテレーションを行うため、大量のチャンク・アセットがある場合はビルド時間に影響する可能性がある。Setによる重複チェックを行い、同一ファイルの二重処理を防止している。

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

マニフェストファイルにはビルド成果物のファイルパスが含まれる。本番環境でマニフェストファイルを公開する場合は、内部パス情報の漏洩に注意が必要。

## 備考

- ManifestPluginはwebpack組み込みプラグインとして提供される
- マニフェストファイルはassetInfo.manifest = trueのフラグ付きで出力される

---

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

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

### 推奨読解順序

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

ManifestPluginが扱うデータ型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ManifestPlugin型定義 | `declarations/plugins/ManifestPlugin.d.ts` | ManifestPluginOptions、ManifestObject、ManifestEntrypoint、ManifestItemの型定義 |

**読解のコツ**: ManifestObjectはentrypoints（エントリポイント情報）とassets（アセット情報）の2つのプロパティを持つ。ManifestItemはfileプロパティ（パス付きファイル名）とオプションのsrcプロパティ（ソースファイル名）を持つ。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ManifestPlugin.js | `lib/ManifestPlugin.js` | プラグイン全体の構造。constructorでのオプション初期化からapplyメソッドでのフック登録まで |

**主要処理フロー**:
1. **31-38行目**: createSchemaValidationによるオプションバリデーション関数の生成
2. **58-69行目**: constructorでオプションのバリデーションとデフォルト値の設定
3. **76-238行目**: applyメソッドでthisCompilationフックにprocessAssetsハンドラを登録

#### Step 3: アセット処理ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ManifestPlugin.js | `lib/ManifestPlugin.js` | processAssetsフック内のマニフェスト構築ロジック |

**主要処理フロー**:
- **44-52行目**: extname関数 - ファイル拡張子を取得（gz/br/mapの二重拡張子対応）
- **93-110行目**: createHashRegExp / removeHash関数 - ハッシュパターンの除去
- **116-120行目**: getName関数 - チャンク名またはIDの取得
- **125-155行目**: エントリポイント情報の収集ロジック
- **168-201行目**: handleFile関数 - 個別アセットの処理（重複チェック、名前解決、prefix適用、filter適用）
- **203-223行目**: チャンクとアセットのイテレーション
- **227-235行目**: generate関数の適用とアセット出力

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

```
ManifestPlugin.apply(compiler)
    |
    +-- compiler.hooks.thisCompilation.tap()
            |
            +-- compilation.hooks.processAssets.tap(STAGE_SUMMARIZE)
                    |
                    +-- compilation.getPath(publicPath)
                    +-- compilation.entrypoints [iterate]
                    |       +-- entrypoint.chunks -> chunk.files
                    |       +-- entrypoint.getParents()
                    +-- compilation.chunks [iterate]
                    |       +-- chunk.auxiliaryFiles -> handleFile()
                    |       +-- chunk.files -> handleFile()
                    +-- compilation.getAssets() [iterate]
                    |       +-- handleFile()
                    +-- options.filter() [optional]
                    +-- options.generate() [optional]
                    +-- options.serialize()
                    +-- compilation.emitAsset()
```

### データフロー図

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

Compilation                  ManifestPlugin
  .entrypoints ---------> エントリポイント情報収集 -------+
  .chunks     ----------> チャンクファイル収集 ----------+---> ManifestObject
  .getAssets() ---------> アセット情報収集 -------------+         |
                                                                  v
ManifestPluginOptions                                     filter/generate
  .prefix     ----------> publicPathプレースホルダー解決          |
  .filename   ---------->                                         v
  .serialize  ----------> JSON.stringify ----------------> manifest.json
                                                         (compilation.emitAsset)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ManifestPlugin.js | `lib/ManifestPlugin.js` | ソース | マニフェスト生成プラグインの本体 |
| ManifestPlugin.check.js | `schemas/plugins/ManifestPlugin.check.js` | スキーマ | オプションバリデーション用コンパイル済みスキーマ |
| ManifestPlugin.json | `schemas/plugins/ManifestPlugin.json` | スキーマ | オプションバリデーション用JSONスキーマ |
| ManifestPlugin.d.ts | `declarations/plugins/ManifestPlugin.d.ts` | 型定義 | TypeScript型定義（ManifestPluginOptions等） |
| Compilation.js | `lib/Compilation.js` | ソース | processAssetsフック、emitAsset、getAssets等のAPI提供元 |
| HotUpdateChunk.js | `lib/HotUpdateChunk.js` | ソース | HotUpdateChunkクラス（除外判定に使用） |
| create-schema-validation.js | `lib/util/create-schema-validation.js` | ソース | スキーマバリデーション関数の生成ユーティリティ |
