# 帳票設計書 9-Stats チャンクグループレポート

## 概要

本ドキュメントは、webpackのエントリーポイントおよびチャンクグループの情報を出力する「Stats チャンクグループレポート」の設計仕様を定義する。

### 本帳票の処理概要

Stats チャンクグループレポートは、エントリーポイントおよび名前付きチャンクグループの名前、関連アセット、サイズ、子グループ等の情報を出力する帳票である。`SIMPLE_EXTRACTORS.compilation.entrypoints` / `compilation.chunkGroups` および `SIMPLE_EXTRACTORS.chunkGroup` により生成される。

**業務上の目的・背景**：webpackのエントリーポイントとチャンクグループの構成を把握し、初期ロード時に必要なアセットの一覧やサイズを確認するために必要である。パフォーマンス最適化（特にSizeLimitsPluginによるサイズ上限チェック）の基礎データとして使用される。

**帳票の利用シーン**：エントリーポイントの構成確認、初期ロードサイズの監視、コード分割戦略のレビュー、パフォーマンスバジェットの管理に利用される。

**主要な出力内容**：
1. チャンクグループ名（name）
2. 関連チャンクID（chunks）
3. アセット一覧（assets: name, size）
4. アセット総サイズ（assetsSize）
5. 補助アセット（auxiliaryAssets）
6. 子チャンクグループ（children）
7. 子アセット（childAssets）
8. サイズ上限超過フラグ（isOverSizeLimit）

**帳票の出力タイミング**：`Stats.toJson()` または `Stats.toString()` 呼び出し時に生成される。

**帳票の利用者**：フロントエンド開発者、パフォーマンスエンジニア。

## 帳票種別

チャンクグループ一覧出力

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLI | `webpack` | ビルド完了時に自動出力 |
| - | Node.js API | プログラム内 | `stats.toJson()` / `stats.toString()` |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（toJson時）/ テキスト（toString時） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A |
| 出力方法 | StatsCompilation.entrypoints / namedChunkGroupsフィールドとして出力 |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

Record<string, StatsChunkGroup>として出力される。キーがチャンクグループ名、値がStatsChunkGroupオブジェクト。

```
{
    "entrypoints": {
        "main": {
            "name":               "main",
            "chunks":             [0, 1],
            "assets":             [{ "name": "main.js", "size": 12345 }],
            "filteredAssets":     0,
            "assetsSize":         12345,
            "auxiliaryAssets":    [{ "name": "main.js.map", "size": 6789 }],
            "children":          { "prefetch": [...] },
            "childAssets":       { "prefetch": ["prefetch.js"] },
            "isOverSizeLimit":   false
        }
    },
    "namedChunkGroups": { ... }
}
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | name | チャンクグループ名 | ChunkGroupInfoWithName.name | 文字列 |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | chunks | チャンクID配列 | chunkGroup.chunks.map(c => c.id) | ID配列 | - |
| 2 | assets | アセット一覧 | uniqueArray(chunkGroup.chunks, c => c.files) | {name, size}[] | - |
| 3 | filteredAssets | フィルタ済みアセット数 | assets.length <= chunkGroupMaxAssets ? 0 : assets.length | 数値 | - |
| 4 | assetsSize | アセット総サイズ | assets.reduce(sizeReducer, 0) | 数値（バイト） | - |
| 5 | auxiliaryAssets | 補助アセット | uniqueOrderedArray(chunks, c => c.auxiliaryFiles) | {name, size}[] | - |
| 6 | filteredAuxiliaryAssets | フィルタ済み補助アセット数 | 条件付き | 数値 | - |
| 7 | auxiliaryAssetsSize | 補助アセット総サイズ | auxiliaryAssets.reduce(sizeReducer, 0) | 数値（バイト） | - |
| 8 | children | 子チャンクグループ | chunkGroup.getChildrenByOrders() | Record<string, StatsChunkGroup[]> | - |
| 9 | childAssets | 子アセット | children内のchunk.filesを集約 | Record<string, string[]> | - |
| 10 | isOverSizeLimit | サイズ上限超過 | SizeLimitsPlugin.isOverSizeLimit(chunkGroup) | 真偽値 | - |

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| entrypoints | エントリーポイント出力設定。`true` / `"auto"` / `false` | No |
| chunkGroups | 名前付きチャンクグループ出力設定 | No |
| chunkGroupAuxiliary | 補助アセット出力設定 | No |
| chunkGroupChildren | 子チャンクグループ出力設定 | No |
| chunkGroupMaxAssets | アセット表示上限数 | No |
| ids | チャンクID出力設定 | No |
| performance | サイズ上限超過判定の有効/無効 | No |

### ソート順

entrypointsはcompilation.entrypointsのMap順序。namedChunkGroupsはcompilation.namedChunkGroupsのMap順序。

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| Compilation | エントリーポイント/チャンクグループ | compilation.entrypoints / namedChunkGroups |
| ChunkGroup | チャンクグループ詳細 | ChunkGroupInfoWithName.chunkGroup |
| ModuleGraph | 子グループ取得 | chunkGroup.getChildrenByOrders(moduleGraph, chunkGraph) |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| assetsSize | assets.reduce((total, { size }) => total + size, 0) | なし | バイト単位 |
| auxiliaryAssetsSize | auxiliaryAssets.reduce((total, { size }) => total + size, 0) | なし | バイト単位 |
| asset.size | compilation.getAsset(name)?.info.size ?? -1 | なし | 不在時-1 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[SIMPLE_EXTRACTORS.compilation.entrypoints] --> B[compilation.entrypointsをArray化]
    B --> C{entrypoints === auto && !chunkGroups?}
    C -->|Yes かつ 5件超| D[出力スキップ]
    C -->|No| E[factory.create compilation.entrypoints 呼び出し]
    E --> F[chunkGroup._ で各チャンクグループの情報抽出]
    F --> G[assets/auxiliaryAssets 算出]
    G --> H[children/childAssets 算出]
    H --> I{performance有効?}
    I -->|Yes| J[isOverSizeLimit判定]
    I -->|No| K[出力]
    J --> K
    K --> L[Record StatsChunkGroup 返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 出力スキップ | entrypoints: "auto" かつ 5件超 かつ chunkGroups: false | undefined返却 | entrypoints: true を明示的に設定 |
| アセット不在 | compilation.getAsset(name)がnull | size: -1 | 正常動作（アセットが見つからない場合） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | エントリーポイント1〜数十、チャンクグループ数十 |
| 目標出力時間 | エントリーポイント数に比例（通常ミリ秒単位） |
| 同時出力数上限 | 1 |

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

チャンクグループ名にはwebpack設定のentry名が反映されるため、アプリケーション内部構造の一部が露出する可能性がある。

## 備考

- `entrypoints: "auto"` の場合、5件以下かつ単純な構成の場合のみ自動出力される
- `chunkGroupMaxAssets` を超えるアセット数の場合、`filteredAssets` にフィルタ数が記録される
- `namedChunkGroups` はentrypointsに含まれないチャンクグループのみ出力される
- 子チャンクグループは`chunkGroupChildren`オプション有効時のみ出力される
- StatsFactory内のmerge hookにより、配列→Record変換が行われる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | 行137-151: `KnownStatsChunkGroup` 型定義。name, chunks, assets, assetsSize, auxiliaryAssets, children, childAssets, isOverSizeLimit |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | 行860-894: `SIMPLE_EXTRACTORS.compilation.entrypoints` - auto判定、Array変換、factory.create |
| 2-2 | DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | 行895-909: `SIMPLE_EXTRACTORS.compilation.chunkGroups` - namedChunkGroups出力 |

**主要処理フロー**:
1. **行869-870**: compilation.entrypointsをChunkGroupInfoWithName配列に変換
2. **行873-888**: `entrypoints === "auto"` の場合、5件超でスキップ、単純構成でもスキップ
3. **行889-893**: `factory.create("compilation.entrypoints", array, context)` で生成

#### Step 3: chunkGroup抽出処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | 行1114-1225: `SIMPLE_EXTRACTORS.chunkGroup._` - assets, auxiliaryAssets, children, childAssets, assetsSize |
| 3-2 | DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | 行1222-1224: `chunkGroup.performance` - isOverSizeLimit判定 |

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

```
SIMPLE_EXTRACTORS.compilation.entrypoints()
    |
    +-- compilation.entrypoints → ChunkGroupInfoWithName[]
    +-- auto判定（5件超 / 単純構成）
    +-- factory.create("compilation.entrypoints", array, context)
            |
            +-- chunkGroup._()
            |       +-- chunkGroup.getChildrenByOrders()
            |       +-- toAsset(name) → { name, size }
            |       +-- assets / auxiliaryAssets 算出
            |       +-- assetsSize / auxiliaryAssetsSize 算出
            |       +-- children → mapObject(children, groups => ...)
            |       +-- childAssets → mapObject(children, groups => ...)
            |
            +-- chunkGroup.performance()
                    +-- SizeLimitsPlugin.isOverSizeLimit(chunkGroup)

SIMPLE_EXTRACTORS.compilation.chunkGroups()
    |
    +-- compilation.namedChunkGroups → ChunkGroupInfoWithName[]
    +-- factory.create("compilation.namedChunkGroups", array, context)
```

### データフロー図

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

compilation.entrypoints        -->  ChunkGroupInfoWithName[]       -->  Record<string, StatsChunkGroup>
compilation.namedChunkGroups   -->  chunkGroup._()                 -->  Record<string, StatsChunkGroup>
  ChunkGroup                   -->    uniqueArray → assets         -->    .assets
  .chunks                     -->    sizeReducer → assetsSize      -->    .assetsSize
  .getChildrenByOrders()      -->    mapObject → children          -->    .children
compilation.getAsset(name)    -->    toAsset → { name, size }      -->    asset size
SizeLimitsPlugin              -->    isOverSizeLimit判定           -->    .isOverSizeLimit
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DefaultStatsFactoryPlugin.js | `lib/stats/DefaultStatsFactoryPlugin.js` | ソース | compilation.entrypoints / chunkGroups / chunkGroup 抽出処理 |
| StatsFactory.js | `lib/stats/StatsFactory.js` | ソース | データ変換パイプライン（merge hookで配列→Record変換） |
| Stats.js | `lib/Stats.js` | ソース | toJson() / toString() エントリーポイント |
| DefaultStatsPrinterPlugin.js | `lib/stats/DefaultStatsPrinterPlugin.js` | ソース | compilation.entrypoints / namedChunkGroupsのテキスト表示 |
| Compilation.js | `lib/Compilation.js` | ソース | entrypoints / namedChunkGroups提供 |
| SizeLimitsPlugin.js | `lib/performance/SizeLimitsPlugin.js` | ソース | isOverSizeLimit判定 |
| ChunkGroup.js | `lib/ChunkGroup.js` | ソース | getChildrenByOrders()メソッド |
