# 機能設計書 52-名前ベースID生成

## 概要

本ドキュメントは、webpackにおける名前ベースID生成機能（NamedModuleIdsPlugin / NamedChunkIdsPlugin）の設計仕様を記述する。モジュールおよびチャンクに対して、ファイルパスやチャンク名に基づいた人間が読みやすい文字列IDを割り当てることで、開発時のデバッグ効率を大幅に向上させる機能である。

### 本機能の処理概要

**業務上の目的・背景**：開発時にバンドル出力を調査する際、数値IDだけではどのモジュールやチャンクを指しているか判別が困難である。名前ベースID生成は、モジュールの相対パスやチャンク名をそのままIDとして使用することで、開発者がバンドル内容を直感的に理解できるようにする。developmentモードでデフォルトで有効となる。

**機能の利用シーン**：開発環境でのデバッグ、バンドル分析、HMR（Hot Module Replacement）時のモジュール識別に利用される。`optimization.moduleIds: 'named'`および`optimization.chunkIds: 'named'`として設定される。

**主要な処理内容**：
1. 未割り当てモジュール/チャンクの一覧を取得する
2. 各モジュールの相対パス（短縮名）を算出する（getShortModuleName）
3. 短縮名が重複する場合はハッシュ付き長名（getLongModuleName）にフォールバックする
4. さらに重複する場合は連番サフィックスを付与する
5. 名前が取得できないモジュール/チャンクには昇順数値IDを割り当てる

**関連システム・外部連携**：ChunkGraph APIを通じてモジュールIDを設定する。module.libIdent()メソッドを利用してモジュール識別名を取得する。

**権限による制御**：特になし。webpack設定のoptimization.moduleIds / optimization.chunkIds により有効化・無効化を制御する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はUIを持たない内部処理であり、直接関連する画面は存在しない |

## 機能種別

計算処理 / 開発支援処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| context | string | No | モジュール識別子を相対化するベースディレクトリ | 未指定時はcompiler.contextを使用 |
| delimiter | string | No | チャンク名の区切り文字（NamedChunkIdsPluginのみ、デフォルト: "-"） | 文字列 |

### 入力データソース

- compilation.modules: コンパイル対象の全モジュール一覧
- compilation.chunks: コンパイル対象の全チャンク一覧
- compilation.outputOptions.hashFunction: ハッシュ関数の指定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| moduleId | string | 各モジュールに割り当てられた名前ベースのID（例: "./src/index.js"） |
| chunkId | string \| number | 各チャンクに割り当てられた名前ベースのID（例: "vendors-node_modules_lodash"） |

### 出力先

ChunkGraphにsetModuleId()で設定、またはChunkオブジェクトのid/idsプロパティに直接設定

## 処理フロー

### 処理シーケンス

```
1. compilation.hooks.moduleIds / chunkIds フック発火
   └─ コンパイル最適化フェーズで呼び出される
2. 使用済みID一覧を収集
   └─ 既にIDが設定されているモジュール/チャンクのIDをSetに格納
3. 短縮名を算出（getShortModuleName / getShortChunkName）
   └─ module.libIdent()で相対パスを取得、数値文字列にはアンダースコアプレフィックスを付与
4. 重複検出と長名フォールバック（assignNames関数）
   └─ 短縮名が重複するアイテムにはハッシュ付き長名を割り当て
5. さらに重複する場合は連番サフィックスを付与
   └─ 名前 + 0, 名前 + 1, ... のように連番を付ける
6. 名前なしモジュール/チャンクに昇順IDを割り当て
   └─ assignAscendingModuleIds / assignAscendingChunkIds
```

### フローチャート

```mermaid
flowchart TD
    A[moduleIds/chunkIdsフック発火] --> B[使用済みID収集]
    B --> C[各アイテムの短縮名算出]
    C --> D{短縮名が重複?}
    D -->|No| E[短縮名をIDとして割り当て]
    D -->|Yes| F[ハッシュ付き長名を算出]
    F --> G{長名も重複?}
    G -->|No| H[長名をIDとして割り当て]
    G -->|Yes| I[連番サフィックス付与]
    I --> J[サフィックス付き名前をIDとして割り当て]
    E --> K{名前なしアイテム?}
    H --> K
    J --> K
    K -->|Yes| L[昇順数値IDを割り当て]
    K -->|No| M[完了]
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | 数値文字列回避 | IDが数値として解釈可能な場合、先頭にアンダースコアを付与する | avoidNumber関数で文字列が21文字以下かつ数値表現の場合 |
| BR-52-02 | 重複解決（2段階） | 短縮名重複時はハッシュ付き長名、さらに重複時は連番サフィックスで解決 | assignNames関数内 |
| BR-52-03 | 名前付きチャンク優先 | chunk.nameが存在する場合はそのままIDとして使用する | NamedChunkIdsPlugin内 |
| BR-52-04 | 100文字制限 | 名前が100文字を超える場合はハッシュで短縮する | shortenLongString関数 |
| BR-52-05 | フォールバック | 名前が取得できないアイテムには昇順数値IDを割り当てる | assignNames戻り値のunnamedModules |

### 計算ロジック

短縮名算出: `module.libIdent({context, associatedObjectForCache})` が優先。取得できない場合は `makePathsRelative(context, module.nameForCondition())` にフォールバック。長名算出: `shortName + "?" + getHash(fullName, 4, hashFunction)`。

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本機能はデータベースを使用しない |

### テーブル別操作詳細

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能は明示的なエラーをスローしない | - |

### リトライ仕様

該当なし。

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

該当なし（同期的なインメモリ処理）

## パフォーマンス要件

- 文字列IDは数値IDに比べてバンドルサイズが大きくなるため、本番環境では推奨されない
- 開発時のビルド速度には大きな影響を与えない

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

- 文字列IDにはファイルパスが含まれるため、本番ビルドでは内部ディレクトリ構造が漏洩する可能性がある
- 本番環境ではdeterministicまたはhashedの使用を推奨

## 備考

- developmentモードのデフォルト設定: `optimization.moduleIds: 'named'`, `optimization.chunkIds: 'named'`
- webpack-dev-serverやHMRとの組み合わせで特に有効

---

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

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

### 推奨読解順序

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

ID生成の名前算出ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IdHelpers.js | `lib/ids/IdHelpers.js` | 名前関連のヘルパー関数（getShortModuleName等）を確認する |

**読解のコツ**: assignNames関数が名前割り当ての中核ロジックであり、2段階の重複解決（短縮名→長名→連番）を理解することが重要。

- **37-52行目**: `avoidNumber`関数 - 数値文字列にアンダースコアプレフィックスを付与
- **58-59行目**: `requestToId`関数 - パス区切り等を正規化してID文字列に変換
- **67-74行目**: `shortenLongString`関数 - 100文字超の名前をハッシュで短縮
- **82-92行目**: `getShortModuleName`関数 - libIdentまたはnameForConditionで短縮名を取得
- **102-111行目**: `getLongModuleName`関数 - 短縮名 + "?" + ハッシュ4桁
- **131-148行目**: `getShortChunkName`関数 - ルートモジュールの短縮名とidNameHintsを結合
- **159-185行目**: `getLongChunkName`関数 - 短縮名と長名の両方を結合
- **298-358行目**: `assignNames`関数 - 2段階重複解決と連番付与

#### Step 2: モジュールID割り当てプラグイン

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NamedModuleIdsPlugin.js | `lib/ids/NamedModuleIdsPlugin.js` | apply()メソッドの全体フロー |

**主要処理フロー**:
1. **42行目**: `compilation.hooks.moduleIds`にタップ
2. **43行目**: `compilation.outputOptions.hashFunction`を取得
3. **50行目**: `getUsedModuleIdsAndModules`で既存ID・未割り当てモジュールを取得
4. **51-59行目**: `assignNames`で名前ベースID割り当て（短縮名→長名→連番）
5. **60-62行目**: 名前なしモジュールに`assignAscendingModuleIds`で昇順IDを割り当て

#### Step 3: チャンクID割り当てプラグイン

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NamedChunkIdsPlugin.js | `lib/ids/NamedChunkIdsPlugin.js` | apply()メソッドの全体フロー |

**主要処理フロー**:
1. **42行目**: `compilation.hooks.chunkIds`にタップ
2. **49行目**: delimiter（デフォルト"-"）を取得
3. **52-58行目**: chunk.nameがある場合はそのままIDに設定、ないチャンクをフィルタ
4. **51-83行目**: `assignNames`で名前ベースID割り当て
5. **84-86行目**: 名前なしチャンクに`assignAscendingChunkIds`で昇順IDを割り当て

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

```
Compiler
    │
    ├─ compilation.hooks.moduleIds
    │      └─ NamedModuleIdsPlugin.apply()
    │             ├─ IdHelpers.getUsedModuleIdsAndModules()
    │             ├─ IdHelpers.assignNames()
    │             │      ├─ IdHelpers.getShortModuleName()
    │             │      │      └─ module.libIdent()
    │             │      └─ IdHelpers.getLongModuleName()
    │             │             └─ IdHelpers.getFullModuleName()
    │             └─ IdHelpers.assignAscendingModuleIds()
    │
    └─ compilation.hooks.chunkIds
           └─ NamedChunkIdsPlugin.apply()
                  ├─ IdHelpers.assignNames()
                  │      ├─ IdHelpers.getShortChunkName()
                  │      └─ IdHelpers.getLongChunkName()
                  ├─ IdHelpers.getUsedChunkIds()
                  └─ IdHelpers.assignAscendingChunkIds()
```

### データフロー図

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

compilation.modules ───────▶ getUsedModuleIdsAndModules() ──▶ [usedIds, modules]
                                                                    │
module.libIdent() ─────────▶ getShortModuleName() ─────────▶ shortName (例: "./src/index.js")
                                                                    │
                              assignNames()
                              ├─ 重複なし ────────────────────▶ shortNameをIDとして設定
                              ├─ 短縮名重複 ──▶ getLongModuleName() ──▶ longName (例: "index.js?a3b4")
                              └─ さらに重複 ──▶ 連番付与 ────────▶ longName + "0", "1", ...
                                                                    │
unnamed modules ───────────▶ assignAscendingModuleIds() ───▶ 昇順数値ID
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NamedModuleIdsPlugin.js | `lib/ids/NamedModuleIdsPlugin.js` | ソース | モジュール向け名前ベースID割り当てプラグイン |
| NamedChunkIdsPlugin.js | `lib/ids/NamedChunkIdsPlugin.js` | ソース | チャンク向け名前ベースID割り当てプラグイン |
| IdHelpers.js | `lib/ids/IdHelpers.js` | ソース | ID生成ヘルパー関数群（assignNames, getShortModuleName等） |
| comparators.js | `lib/util/comparators.js` | ソース | ソート用比較関数（compareModulesByIdentifier, compareChunksNatural） |
| identifier.js | `lib/util/identifier.js` | ソース | パス相対化ユーティリティ（makePathsRelative） |
| createHash.js | `lib/util/createHash.js` | ソース | ハッシュ関数抽象化（長名生成で使用） |
| ChunkGraph.js | `lib/ChunkGraph.js` | ソース | モジュールID設定API（setModuleId） |
