# 帳票設計書 15-SourceMapDevToolPlugin ソースマップ

## 概要

本ドキュメントは、webpackビルド成果物のソースマップ（.mapファイル）を生成・出力する「SourceMapDevToolPlugin ソースマップ」の設計仕様を定義するものである。

### 本帳票の処理概要

SourceMapDevToolPlugin ソースマップは、webpackビルドで生成されたJavaScript/CSSアセットに対して、デバッグ用のソースマップを生成・出力する帳票である。ソースマップはビルド後のコードとオリジナルのソースコードとの対応関係を記録したJSON形式のファイルであり、ブラウザのDevToolsでのデバッグを可能にする。外部ファイル（.mapファイル）としての出力とインラインData URI形式での埋め込みの両方に対応する。

**業務上の目的・背景**：バンドル・ミニファイ・トランスパイルされたコードのデバッグは困難であるため、オリジナルのソースコードとの対応関係を提供するソースマップが必要である。開発環境でのデバッグ効率を大幅に向上させる。

**帳票の利用シーン**：開発環境でのデバッグ、ステージング環境でのエラートレース、本番環境でのエラーモニタリング（Sentry等）など。

**主要な出力内容**：
1. ソースマップファイル（.map）- Source Map v3仕様に準拠したJSONファイル
2. ソースマッピングURLコメント - アセットファイル末尾に付与される参照コメント
3. debugId - ソースとソースマップの対応を一意に識別するID（オプション）

**帳票の出力タイミング**：webpackビルドの `processAssets` フック（PROCESS_ASSETS_STAGE_DEV_TOOLING ステージ）で実行される。

**帳票の利用者**：フロントエンド開発者、QAエンジニア、DevOpsエンジニア。

## 帳票種別

ソースマップ（デバッグ支援ファイル）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | webpack設定 | `devtool: 'source-map'` または `plugins: [new SourceMapDevToolPlugin(options)]` | ビルド実行時に自動出力 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON（Source Map v3） |
| 用紙サイズ | N/A（データ出力） |
| 向き | N/A |
| ファイル名 | options.filename で指定（例: `[file].map[query]`）。未指定の場合はインラインData URI |
| 出力方法 | ビルド成果物としてemit / インラインData URI埋め込み |
| 文字コード | UTF-8 |

## 帳票レイアウト

### レイアウト概要

ソースマップは Source Map v3 仕様に準拠したJSONオブジェクトとして出力される。

```
SourceMap (v3)
├── version: 3
├── file: string (対象ファイル名)
├── sourceRoot: string (ソースルート)
├── sources: string[] (ソースファイル名一覧)
├── sourcesContent?: string[] (ソースコード内容)
├── names: string[] (識別子名一覧)
├── mappings: string (Base64 VLQエンコードされたマッピング)
├── ignoreList?: number[] (無視するソースのインデックス)
└── debugId?: string (デバッグID、オプション)
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | file | 対象ファイル名 | task.file（contenthash使用時はマスク処理） | 文字列 |
| 2 | sourceRoot | ソースルートパス | options.sourceRoot \|\| "" | 文字列 |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | sources | ソースファイル名一覧 | moduleToSourceNameMapping | 文字列配列 | - |
| 2 | sourcesContent | ソースコード内容 | オリジナルソース（noSources時はundefined） | 文字列配列 | - |
| 3 | mappings | マッピング情報 | webpack-sources ライブラリが生成 | Base64 VLQ文字列 | - |
| 4 | ignoreList | 無視するソースのインデックス | options.ignoreList ルールでマッチしたソース | 数値配列 | - |
| 5 | debugId | デバッグID | generateDebugId(source, file) | 文字列 | - |

### フッター部

該当なし。ただし、対象アセットファイルの末尾にソースマッピングURLコメントが追加される。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ファイルマッチ | options.test（デフォルト: .js/.mjs/.cjs/.css）にマッチするアセット | Yes |
| ソースマップ存在 | asset.sourceAndMap() または asset.map() が有効なソースマップを返すこと | Yes |
| 既存ソースマップなし | asset.info.related.sourceMap が未設定であること | Yes |
| include/exclude | options.include / options.exclude によるファイルフィルタ | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | アセットのイテレーション順 | - |

### 改ページ条件

N/A

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| compilation.chunks | チャンクとファイルの対応 | chunk.files, chunk.auxiliaryFiles |
| compilation assets | アセットとソースの対応 | compilation.getAsset(file) |
| compilation cache | ソースマップキャッシュ | compilation.getCache("SourceMapDevToolPlugin") |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| sourceMapUrl | publicPath指定時: options.publicPath + sourceMapFile、未指定時: relative(dirname(file), sourceMapFile) | なし | 外部ファイル時のみ |
| sourceMapContentHash | createHash(hashFunction).update(sourceMapString).digest("hex") | なし | contenthash使用時のみ |
| debugId | generateDebugId(source, sourceMap.file) | なし | debugIds オプション有効時のみ |
| sourceMappingURLComment | CSS: `/*#sourceMappingURL=[url]*/`、JS: `//# sourceMappingURL=[url]` | なし | CSSファイルはコメント形式が異なる |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[processAssets フック] --> B[アセットファイル収集 matchObject]
    B --> C[各ファイルについて]
    C --> D{既存ソースマップあり?}
    D -->|Yes| C
    D -->|No| E{キャッシュヒット?}
    E -->|Yes| F[キャッシュからアセット復元]
    E -->|No| G[getTaskForFile でソースマップタスク生成]
    G --> H[モジュール名マッピング生成]
    H --> I[重複名解決]
    I --> J{sourceMapFilename 指定?}
    J -->|Yes| K[外部 .map ファイル生成]
    J -->|No| L[インライン Data URI 生成]
    K --> M[sourceMappingURL コメント追加]
    L --> M
    M --> N[キャッシュ保存]
    N --> O[compilation.emitAsset / updateAsset]
    F --> O
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| append不正（外部ファイルなし） | filename未指定かつappend=false | "SourceMapDevToolPlugin: append can't be false when no filename is provided" | filenameを指定するかappendを有効にする |
| append不正（関数指定） | filename未指定かつappendが関数 | "SourceMapDevToolPlugin: append can't be a function when no filename is provided" | filenameを指定する |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | アセット数に依存（数件〜数十件） |
| 目標出力時間 | キャッシュ利用で高速化、初回はソースマップ生成のため数秒 |
| 同時出力数上限 | N/A（asyncLib.each で並列処理） |

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

ソースマップにはオリジナルのソースコードが含まれる（`noSources` オプションで除外可能）。本番環境では以下の対策を検討する必要がある：
- `noSources: true` でソースコード内容を除外
- ソースマップファイルへのアクセスをIP制限
- `append: false` でソースマッピングURLコメントを除去
- Sentry等のエラーモニタリングサービスへの非公開アップロード

## 備考

- `options.module` が true の場合、モジュール単位のソースマップが生成される。false の場合はローダー変換前のソースマップが使用される。
- `options.columns` が true の場合、列レベルのマッピングが生成される。false の場合は行レベルのみ。
- CSSファイルの場合、ソースマッピングURLコメントの形式が `/*...*/` に自動変換される（507行目）。
- contenthash 使用時は循環依存を避けるため、sourceMap.file のハッシュ部分がマスクされる（483-492行目）。

---

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

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

### 推奨読解順序

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

ソースマップの入出力データ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SourceMapDevToolPlugin.js | `lib/SourceMapDevToolPlugin.js` | SourceMapTask 型定義（47-54行目）: asset, assetInfo, modules, source, file, sourceMap, cacheItem |

**読解のコツ**: SourceMapTask はソースマップ生成の作業単位。各アセットファイルに対して1つのタスクが生成され、非同期処理で並列実行される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SourceMapDevToolPlugin.js | `lib/SourceMapDevToolPlugin.js` | コンストラクタ（143-165行目）でオプション設定、apply()（172-643行目）でプラグイン登録 |

**主要処理フロー**:
1. **143-165行目**: コンストラクタでデフォルト値設定（sourceMapFilename, sourceMappingURLComment, moduleFilenameTemplate, namespace）
2. **191行目**: `compiler.hooks.compilation.tap` で compilation フックに登録
3. **194-198行目**: `processAssets` フック（PROCESS_ASSETS_STAGE_DEV_TOOLING, additionalAssets: true）に登録

#### Step 3: ソースマップタスク生成

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SourceMapDevToolPlugin.js | `lib/SourceMapDevToolPlugin.js` | getTaskForFile 関数（91-134行目）でソースマップタスクを生成 |

**主要処理フロー**:
- **106-113行目**: asset.sourceAndMap() または asset.map() でソースマップ取得
- **114行目**: ソースマップが存在しない場合は undefined を返す
- **118-123行目**: ソースのパスを解決してモジュール参照に変換

#### Step 4: ソースマップ出力処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SourceMapDevToolPlugin.js | `lib/SourceMapDevToolPlugin.js` | タスク処理とファイル出力（426-638行目） |

**主要処理フロー**:
- **445-448行目**: moduleToSourceNameMapping からソースファイル名を設定
- **449-469行目**: ignoreList の生成
- **471-474行目**: noSources / sourceRoot の設定
- **496-509行目**: CSS ファイルのコメント形式変換
- **522-587行目**: 外部ファイルとして出力する場合の処理
- **588-618行目**: インライン Data URI として埋め込む場合の処理

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

```
SourceMapDevToolPlugin.apply(compiler)
    │
    ├─ SourceMapDevToolModuleOptionsPlugin.apply(compilation)
    │
    └─ compilation.hooks.processAssets.tapAsync (STAGE_DEV_TOOLING)
           │
           ├─ fileToChunk マッピング生成
           │
           ├─ matchObject によるファイルフィルタリング
           │
           ├─ 各ファイルについて (asyncLib.each)
           │      │
           │      ├─ キャッシュチェック
           │      │
           │      └─ getTaskForFile()
           │             ├─ asset.sourceAndMap() / asset.map()
           │             └─ ソースパス解決 → モジュール参照
           │
           ├─ 重複ソース名解決 (fallbackModuleFilenameTemplate)
           │
           └─ 各タスクについて (asyncLib.each)
                  │
                  ├─ sources / ignoreList / sourceRoot 設定
                  │
                  ├─ CSS コメント形式変換
                  │
                  ├─ debugId 生成（オプション）
                  │
                  ├─ JSON.stringify(sourceMap)
                  │
                  ├─ 外部ファイル or インライン分岐
                  │      ├─ 外部: compilation.emitAsset(.map)
                  │      └─ インライン: Data URI 埋め込み
                  │
                  ├─ compilation.updateAsset (コメント追加)
                  │
                  └─ cacheItem.store (キャッシュ保存)
```

### データフロー図

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

Asset Source               SourceMapDevToolPlugin           ソースマップファイル (.map)
(sourceAndMap/map)         processAssets フック             + 更新されたアセット
       │                   ────────────────────▶            (sourceMappingURL コメント付き)
       │                   ソースマップ抽出
       │                   + モジュール名解決
       │                   + 重複名解決
       │                   + ignoreList 生成
       │                   + debugId 生成
       │                   + JSON シリアライズ
       │
compilation.cache ◀────── キャッシュ保存/復元
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SourceMapDevToolPlugin.js | `lib/SourceMapDevToolPlugin.js` | ソース | ソースマップ生成のメインロジック |
| SourceMapDevToolModuleOptionsPlugin.js | `lib/SourceMapDevToolModuleOptionsPlugin.js` | ソース | モジュールレベルのソースマップオプション設定 |
| ModuleFilenameHelpers.js | `lib/ModuleFilenameHelpers.js` | ソース | ファイル名テンプレート処理・マッチング |
| generateDebugId.js | `lib/util/generateDebugId.js` | ソース | debugId の生成 |
| Compilation.js | `lib/Compilation.js` | ソース | アセット管理・キャッシュ機能 |
