# 機能設計書 29-アセットモジュール

## 概要

本ドキュメントは、webpackのAssetModulesPluginによる画像・フォント等のアセットファイルをモジュールとして処理する機能について記述する。

### 本機能の処理概要

AssetModulesPluginは、画像、フォント、動画、音声などの非JavaScriptアセットファイルをwebpackモジュールとして処理する機能を提供する。アセットのサイズに応じてインライン（Data URL）化するか、別ファイルとして出力するかを自動判定する。

**業務上の目的・背景**：Webアプリケーションでは画像やフォントなどの静的アセットを適切に管理する必要がある。小さなアセットはData URLとしてインライン化することでHTTPリクエスト数を削減し、大きなアセットは別ファイルとして出力することでキャッシュ効率を向上させる。従来のfile-loader/url-loader/raw-loaderの機能を統合し、webpack組み込みとして提供する。

**機能の利用シーン**：`module.rules` の `type` プロパティで `'asset'`（自動判定）、`'asset/resource'`（ファイル出力）、`'asset/inline'`（Data URL）、`'asset/source'`（ソース文字列）、`'asset/bytes'`（バイト列）を指定して利用する。

**主要な処理内容**：
1. 5種類のアセットモジュールタイプに対応するパーサーとジェネレーターを登録する
2. AssetParserでアセットのインライン/リソース判定を行う
3. AssetGeneratorでData URL生成またはファイル出力用コードを生成する
4. renderManifestフックでアセットファイルの出力情報を提供する

**関連システム・外部連携**：NormalModuleFactoryの createParser/createGenerator/createModuleClass フックを利用してアセットモジュールの処理パイプラインを構築する。mime-typesパッケージによるMIMEタイプ自動判定。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに該当する画面なし |

## 機能種別

データ変換処理（アセットファイルのモジュール化・インライン化・ファイル出力）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parser.dataUrlCondition | object \| function \| boolean | No | インライン判定条件 | maxSize: number（デフォルト8096） |
| generator.dataUrl | object \| function | No | Data URL生成オプション | encoding, mimetype |
| generator.filename | string | No | 出力ファイル名テンプレート | - |
| generator.publicPath | string \| function | No | 公開パス | - |
| generator.outputPath | string \| function | No | 出力パス | - |
| generator.emit | boolean | No | ファイルを出力するか | デフォルトtrue |

### 入力データソース

webpack設定の `module.rules[].type` および `module.rules[].parser` / `module.rules[].generator` オプション。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JavaScript source | Source | `module.exports = "data:..."` または `module.exports = __webpack_require__.p + "filename"` |
| Asset file | Buffer | リソースモードの場合、別ファイルとして出力されるアセット |

### 出力先

JavaScript出力はバンドルファイル内、アセットファイルは出力ディレクトリに個別ファイルとして出力される。

## 処理フロー

### 処理シーケンス

```
1. プラグイン適用（apply）
   ├─ NormalModuleFactory.createModuleClass フックで NormalModule を返却
   ├─ NormalModuleFactory.createParser フックでタイプ別パーサーを登録
   │   ├─ asset: AssetParser(dataUrlCondition オブジェクト)
   │   ├─ asset/inline: AssetParser(true)
   │   ├─ asset/resource: AssetParser(false)
   │   ├─ asset/source: AssetSourceParser
   │   └─ asset/bytes: AssetBytesParser
   ├─ NormalModuleFactory.createGenerator フックでタイプ別ジェネレーターを登録
   │   ├─ asset/asset/inline/asset/resource: AssetGenerator
   │   ├─ asset/source: AssetSourceGenerator
   │   └─ asset/bytes: AssetBytesGenerator
   └─ compilation.hooks.renderManifest フックでアセット出力情報を提供
2. パース処理（AssetParser.parse）
   ├─ buildInfo.strict = true
   ├─ buildMeta.exportsType = "default"
   └─ dataUrlCondition に基づき buildInfo.dataUrl を決定
       ├─ function: ソースとファイル名から判定
       ├─ boolean: 直接設定
       └─ object (maxSize): バイトサイズで判定
3. コード生成（AssetGenerator.generate）
   ├─ dataUrl=true: Data URL生成
   │   ├─ MIMEタイプ決定
   │   ├─ エンコーディング（base64/URI）
   │   └─ module.exports = "data:..."
   └─ dataUrl=false: リソースファイル生成
       ├─ コンテンツハッシュ計算
       ├─ ファイル名テンプレート解決
       ├─ 公開パス解決
       └─ module.exports = __webpack_require__.p + "filename"
```

### フローチャート

```mermaid
flowchart TD
    A[アセットファイル読み込み] --> B[AssetParser.parse]
    B --> C{dataUrlCondition判定}
    C -->|maxSize以下| D[dataUrl = true]
    C -->|maxSize超過| E[dataUrl = false]
    D --> F[AssetGenerator.generate]
    E --> F
    F --> G{dataUrl?}
    G -->|true| H[Data URL生成]
    G -->|false| I[ファイル出力コード生成]
    H --> J["module.exports = data:..."]
    I --> K["module.exports = publicPath + filename"]
    I --> L[renderManifestでファイル出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトmaxSize | 8096バイト（約8KB）以下でインライン化 | type='asset', dataUrlConditionオブジェクト |
| BR-02 | デフォルトエンコーディング | base64エンコーディング | encoding未指定時 |
| BR-03 | MIMEタイプ自動判定 | ファイル拡張子からmime-typesで判定 | mimetype未指定時 |
| BR-04 | CSS URL対応 | CSS内のurl()参照時はCSS_URL_TYPE形式で出力 | CSSモジュールから参照時 |
| BR-05 | 連結スコープ対応 | ConcatenationScope利用時はNAMESPACE_OBJECT_EXPORTとして登録 | Scope Hoisting時 |
| BR-06 | sideEffectFree | オプション指定時にモジュールをsideEffectFreeとしてマーク | sideEffectFree=true |

### 計算ロジック

Data URLの構築: `data:{mimeType};{encoding},{encodedContent}`
- base64: `source.buffer().toString("base64")`
- URI: `encodeURIComponent(content)`

コンテンツハッシュ: `createHash(hashFunction).update(hashSalt).update(source.buffer()).digest(hashDigest)`

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | MIMEタイプが判定できない場合 | "DataUrl can't be generated automatically, because there is no mimetype for..." |
| - | Error | サポートされないエンコーディング | "Unsupported encoding '...'" |

### リトライ仕様

リトライ処理はない。

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

トランザクション管理はない。

## パフォーマンス要件

大量のアセットファイルを処理する場合、コンテンツハッシュの計算やbase64エンコーディングがCPU負荷となりうる。アセット数に比例して処理時間が増加する。

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

Data URLにはファイル内容がそのまま含まれるため、機密情報を含むファイルのインライン化には注意が必要。

## 備考

- Asset Modulesはwebpack 5で導入され、file-loader/url-loader/raw-loaderを置き換える
- getTypes()メソッドでモジュールの参照元（JavaScript/CSS）に応じて適切なソースタイプを返す
- emit=false指定時はファイル出力せずData URL形式のみ（npm publishなど配布用ビルド向け）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AssetParser.js | `lib/asset/AssetParser.js` | dataUrlCondition型 - boolean/object/function |
| 1-2 | AssetGenerator.js | `lib/asset/AssetGenerator.js` | コンストラクタ（202-223行目）- dataUrlOptions, filename, publicPath, outputPath, emit |

**読解のコツ**: `buildInfo.dataUrl` がインライン判定結果を保持する重要なフラグ。パーサーが設定し、ジェネレーターが参照する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AssetModulesPlugin.js | `lib/asset/AssetModulesPlugin.js` | applyメソッド（107-355行目）全体 |

**主要処理フロー**:
1. **112-133行目**: createModuleClass - 5タイプのNormalModule生成
2. **135-179行目**: createParser - タイプ別パーサー登録
3. **181-242行目**: createGenerator - タイプ別ジェネレーター登録
4. **244-332行目**: renderManifest - アセットファイル出力情報提供

#### Step 3: パーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AssetParser.js | `lib/asset/AssetParser.js` | parseメソッド（35-70行目）- dataUrlConditionの評価 |

**主要処理フロー**:
- **50-54行目**: function型: カスタム判定関数の呼び出し
- **55-56行目**: boolean型: 直接設定
- **57-65行目**: object型: maxSizeによるバイトサイズ比較

#### Step 4: ジェネレーターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AssetGenerator.js | `lib/asset/AssetGenerator.js` | generateメソッド（529-643行目）- コード生成の分岐 |
| 4-2 | AssetGenerator.js | `lib/asset/AssetGenerator.js` | generateDataUri（468-522行目）- Data URL生成 |
| 4-3 | AssetGenerator.js | `lib/asset/AssetGenerator.js` | getFilenameWithInfo（280-322行目）- ファイル名解決 |

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

```
AssetModulesPlugin.apply()
    │
    ├─ normalModuleFactory.hooks.createModuleClass
    │      └─ new NormalModule(createData)
    │
    ├─ normalModuleFactory.hooks.createParser
    │      ├─ asset: new AssetParser(dataUrlCondition)
    │      ├─ asset/inline: new AssetParser(true)
    │      ├─ asset/resource: new AssetParser(false)
    │      ├─ asset/source: new AssetSourceParser()
    │      └─ asset/bytes: new AssetBytesParser()
    │
    ├─ normalModuleFactory.hooks.createGenerator
    │      ├─ asset/inline/resource: new AssetGenerator(...)
    │      ├─ asset/source: new AssetSourceGenerator(...)
    │      └─ asset/bytes: new AssetBytesGenerator(...)
    │
    └─ compilation.hooks.renderManifest
           └─ アセットファイル出力情報の提供
```

### データフロー図

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

アセットファイル ──────────▶ AssetParser.parse() ──────▶ buildInfo.dataUrl (boolean)
    (画像/フォント等)          (インライン判定)

buildInfo.dataUrl ─────────▶ AssetGenerator.generate()
    true ──────────────────▶   generateDataUri() ──────▶ "data:image/png;base64,..."
    false ─────────────────▶   getFilenameWithInfo() ──▶ __webpack_require__.p + "file.png"
                               getAssetPathWithInfo()

アセットソース ────────────▶ renderManifest ────────────▶ 出力ファイル（dist/file.png）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AssetModulesPlugin.js | `lib/asset/AssetModulesPlugin.js` | ソース | アセットモジュール機能のメインプラグイン |
| AssetParser.js | `lib/asset/AssetParser.js` | ソース | インライン/リソース判定パーサー |
| AssetGenerator.js | `lib/asset/AssetGenerator.js` | ソース | Data URL/ファイル出力コード生成 |
| AssetSourceParser.js | `lib/asset/AssetSourceParser.js` | ソース | ソース文字列パーサー |
| AssetSourceGenerator.js | `lib/asset/AssetSourceGenerator.js` | ソース | ソース文字列ジェネレーター |
| AssetBytesParser.js | `lib/asset/AssetBytesParser.js` | ソース | バイト列パーサー |
| AssetBytesGenerator.js | `lib/asset/AssetBytesGenerator.js` | ソース | バイト列ジェネレーター |
| RawDataUrlModule.js | `lib/asset/RawDataUrlModule.js` | ソース | Data URLモジュール |
