# 通知設計書 10-ModuleBuildError

## 概要

本ドキュメントは、Webpackにおけるモジュールビルド（ローダー実行）時に発生するエラーを表す `ModuleBuildError` クラスの設計仕様を記述する。ローダーパイプラインの実行失敗やローダーの戻り値が不正な場合に生成される。

### 本通知の処理概要

ModuleBuildError は、NormalModuleの `_doBuild` メソッド内でローダーパイプラインの実行が失敗した場合に生成されるエラークラスである。ModuleError（No.7）がローダーが自発的にemitErrorで報告するエラーであるのに対し、ModuleBuildErrorはローダー自体の実行が例外をスローした場合（ビルドプロセスの障害）を表す。

**業務上の目的・背景**：Webpackのビルドプロセスでは、各モジュールはローダーパイプライン（babel-loader, css-loader, ts-loader等）を通じてトランスパイル・変換される。ローダーの実行が失敗した場合（構文エラー、設定ミス、ローダーのバグなど）、モジュールのビルドが完了できないため、ビルド全体が失敗する可能性がある。ModuleBuildErrorは、ローダー実行の失敗を詳細なスタックトレース情報と共に開発者に通知し、問題の迅速な特定を支援する。

**通知の送信タイミング**：NormalModuleの `_doBuild` メソッド内の `processResult` コールバックで、(1) ローダーパイプラインがエラーを返した時（NormalModule.js 行961）、(2) 最終ローダーがBufferでもStringでもない値を返した時（NormalModule.js 行990）。

**通知の受信者**：Webpackビルドを実行した開発者。Stats出力を通じてエラーとして表示される。

**通知内容の概要**：「Module build failed (from {ローダー名}): {エラーメッセージまたはスタックトレース}」の形式で表示される。hideStackフラグの有無によって、完全なスタックトレースを表示するか、エラーメッセージのみ表示してスタックトレースをdetailsに格納するかが制御される。

**期待されるアクション**：開発者は、(1) ソースコードの構文エラーを修正する、(2) ローダーの設定（webpack.config.jsのmodule.rules）を見直す、(3) ローダーパッケージを更新する、(4) ローダーの互換性を確認する。

## 通知種別

ビルドプロセス内エラー通知（コンソール出力 / Stats JSON / Stats HTML）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コールバックのerr引数として返却） |
| 優先度 | 高（エラー、ビルド失敗に直結） |
| リトライ | なし |

### 送信先決定ロジック

NormalModuleの `_doBuild` メソッド内の `processResult` コールバックで生成され、`callback(error)` として上位に返却される。上位のビルドフローでCompilation.errorsに追加されるか、モジュールのエラーとしてマークされる。

## 通知テンプレート

### メール通知の場合

該当なし（ビルド出力として表示される）。

### 本文テンプレート

fromパラメータがある場合:
```
Module build failed (from {from}):
{エラー内容}
```

fromパラメータがない場合:
```
Module build failed: {エラー内容}
```

hideStack=false の場合のエラー内容:
```
{cutOffLoaderExecution(err.stack)}
```

hideStack=true の場合のエラー内容:
```
{err.message}
```
(スタックトレースはdetailsプロパティに格納)

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| err | 元のエラーオブジェクトまたは文字列 | ローダーパイプラインからのエラー | Yes |
| from | エラー発生元のローダー名 | requestShortener.shorten(currentLoader.loader) | No |
| name | エラー名称（固定値 "ModuleBuildError"） | クラス内で設定 | Yes |
| error | 元のエラーオブジェクト参照 | コンストラクタ引数のerr | Yes |
| details | スタックトレース（hideStack=trueの場合） | cutOffLoaderExecution(err.stack) | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ローダー実行エラー | processResultコールバックのerr | ローダーパイプラインがエラーを返した場合 | NormalModule.js 行956-968 |
| 不正な戻り値 | 最終ローダーの戻り値チェック | BufferでもStringでもない値が返された場合 | NormalModule.js 行979-991 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ローダー実行成功 | ローダーパイプラインが正常に完了し、Buffer/Stringを返した場合 |
| stats.errors=false | Stats出力でエラー表示が抑制される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[NormalModule._doBuild] --> B[runLoaders実行]
    B --> C{ローダーエラー?}
    C -->|Yes| D[NonErrorEmittedErrorラップ（非Error時）]
    C -->|No| E[processResult で戻り値チェック]
    D --> F[ModuleBuildError生成 from付き]
    E --> G{Buffer/String?}
    G -->|Yes| H[正常処理継続]
    G -->|No| I[ModuleBuildError生成 fromなし]
    F --> J{err.hideStack?}
    I --> J
    J -->|false| K[messageにスタックトレース全体]
    J -->|true| L[messageにerr.message、detailsにスタック]
    K --> M[callback error として返却]
    L --> M
    M --> N[上位でCompilation.errorsに追加]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースは使用しない）。

### 更新テーブル一覧

該当なし（データベースは使用しない）。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 構文エラー | ソースコードにJavaScript/TypeScript等の構文エラーがある | ソースコードを修正する |
| ローダー設定エラー | ローダーの設定（options）が不正 | webpack.config.jsのmodule.rulesを見直す |
| ローダー互換性エラー | ローダーのバージョン不整合 | ローダーパッケージを更新する |
| 不正な戻り値 | 最終ローダーがBuffer/String以外を返した | ローダーの実装を確認・修正する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ビルド実行時に即座に出力される）。

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

スタックトレースにローダーのファイルパスやプロジェクトの内部構造が含まれるため、CI/CD環境のログ公開時には注意が必要。`hideStack=true` の場合、スタックトレースがdetailsに格納されるため、Stats出力の設定で表示を制限できる。

## 備考

- `makeSerializable` によりキャッシュのシリアライズ/デシリアライズに対応している。
- serialize/deserialize メソッドでは `error` プロパティも保存・復元される。
- `ErrorWithHideStack` 型がこのファイル内で定義されている（行15: `@typedef {Error & { hideStack?: boolean }} ErrorWithHideStack`）。この型は ModuleDependencyError や ModuleDependencyWarning からもインポートされている。
- `cutOffLoaderExecution` 関数（ErrorHelpers.js）により、スタックトレースから "LOADER_EXECUTION" フラグ以降が除去され、ローダー内部のスタックのみが表示される。
- コンストラクタのerrパラメータは `string | ErrorWithHideStack` のユニオン型であり、文字列の場合は `String(err)` でメッセージに変換される。
- fromパラメータの生成にはrequestShortener.shorten()が使用され、ローダーパスが短縮表示される。

---

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

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

### 推奨読解順序

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

ModuleBuildErrorの複雑なメッセージ構築ロジックとhideStackの分岐を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ModuleBuildError.js | `lib/ModuleBuildError.js` | コンストラクタ（行22-56）の詳細なメッセージ構築ロジック、hideStackによる分岐、ErrorWithHideStack型定義（行15） |

**読解のコツ**: コンストラクタ（行22-56）には多重の条件分岐がある。(1) errがオブジェクトか文字列か、(2) err.stackが存在するか、(3) err.hideStackがtrueか、(4) err.messageが存在するか、の4段階の分岐を追う必要がある。特にhideStack=trueの場合、スタックトレースがdetailsに格納され、messageにはerr.messageのみが含まれる点が重要。

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

NormalModuleの _doBuild 内でのModuleBuildError生成フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NormalModule.js | `lib/NormalModule.js` | _doBuildメソッド（行941）、processResultコールバック（行955-968）、戻り値チェック（行979-991） |

**主要処理フロー**:
1. **行941**: `_doBuild(options, compilation, resolver, fs, hooks, callback)` メソッド開始
2. **行942-948**: `_createLoaderContext` でローダーコンテキスト生成
3. **行955**: `processResult` コールバック定義
4. **行956-968**: ローダーエラー時のModuleBuildError生成
   - **行957-958**: 非Error型の場合、NonErrorEmittedErrorでラップ
   - **行960**: `getCurrentLoader(loaderContext)` で現在のローダーを取得
   - **行961-967**: `new ModuleBuildError(err, { from: ... })` でインスタンス生成
   - **行968**: `callback(error)` でエラーを返却
5. **行979-991**: 最終ローダーの戻り値チェック
   - **行979**: `!Buffer.isBuffer(source) && typeof source !== "string"` の条件
   - **行990**: `new ModuleBuildError(err)` で fromなしのインスタンス生成

#### Step 3: スタックトレース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ErrorHelpers.js | `lib/ErrorHelpers.js` | cutOffLoaderExecution関数（行31）: "LOADER_EXECUTION" フラグでスタックを切断 |

**主要処理フロー**:
- **行31**: `cutOffLoaderExecution` = `cutOffByFlag(stack, "LOADER_EXECUTION")`
- **行17-25**: `cutOffByFlag` はフラグを含む行以降を切り捨てる

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

```
NormalModule._doBuild()                    [NormalModule.js 行941]
    │
    ├─ _createLoaderContext()               [行942]
    │
    ├─ runLoaders()
    │      │
    │      └─ processResult(err, result)    [行955]
    │             │
    │             ├─ (err存在時)
    │             │      ├─ new NonErrorEmittedError()  [行958] (非Error時)
    │             │      └─ new ModuleBuildError(err, {from})  [行961]
    │             │             ├─ cutOffLoaderExecution(err.stack)  [行31]
    │             │             └─ hideStack分岐  [行33-45]
    │             │
    │             └─ (戻り値不正時)
    │                    └─ new ModuleBuildError(err)  [行990]
    │
    └─ callback(error)                      [行968, 991]
```

### データフロー図

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

runLoaders()             ───> processResult(err)          ───> ModuleBuildError
  ローダーパイプライン          │                                │
  実行結果                     │ エラー時                       │
                               v                               │
err (Error/string)       ───> メッセージ構築               ───> │
                               "Module build failed"            │
from: ローダー名          ───> "(from X): "               ───> │
  (requestShortener)                                           │
                               │                               │
err.stack               ───> cutOffLoaderExecution()      ───> │
                               LOADER_EXECUTION以降を除去       │
                               │                               │
                               │ hideStack分岐                  │
                               ├─ false: message にスタック全体  │
                               └─ true:  details にスタック      │
                                         message にメッセージ    │
                                                               v
                                                         callback(error)
                                                               │
                                                               v
                                                         Compilation.errors[]
                                                               │
                                                               v
                                                         Stats出力(エラー)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ModuleBuildError.js | `lib/ModuleBuildError.js` | ソース | モジュールビルドエラークラス定義、ErrorWithHideStack型定義 |
| WebpackError.js | `lib/WebpackError.js` | ソース | 基底エラー/警告クラス |
| ErrorHelpers.js | `lib/ErrorHelpers.js` | ソース | cutOffLoaderExecution関数 |
| NormalModule.js | `lib/NormalModule.js` | ソース | _doBuildメソッド、ローダー実行とエラーハンドリング |
| makeSerializable.js | `lib/util/makeSerializable.js` | ソース | シリアライズ登録ユーティリティ |
| Compilation.js | `lib/Compilation.js` | ソース | errors配列の管理 |
