# 通知設計書 9-ModuleNotFoundError

## 概要

本ドキュメントは、Webpackにおいて要求されたモジュールが見つからない場合に発生するエラーを表す `ModuleNotFoundError` クラスの設計仕様を記述する。Node.jsコアモジュールのPolyfill情報を含む詳細なガイダンスメッセージを提供する。

### 本通知の処理概要

ModuleNotFoundError は、import/require文で指定されたモジュールが解決（resolve）できない場合に発生するエラークラスである。特にWebpack 5以降でNode.jsコアモジュールのPolyfillが自動的に含まれなくなった変更（BREAKING CHANGE）に対する詳細なガイダンスメッセージを提供する。

**業務上の目的・背景**：Webpackのモジュール解決プロセスで、指定されたモジュールが見つからない場合は致命的なエラーとなる。特にWebpack 4からWebpack 5への移行時に、Node.jsコアモジュール（crypto, buffer, path等）のPolyfillが自動で含まれなくなったため、多くのプロジェクトでこのエラーが発生した。ModuleNotFoundErrorは、単なる「モジュールが見つからない」というエラーだけでなく、Webpack 5での移行ガイダンス（resolve.fallbackの設定方法、Polyfillパッケージのインストール方法）を含む詳細な修正方法を提供する。

**通知の送信タイミング**：(1) Compilationのモジュールファクトリ実行でモジュール解決に失敗した時（Compilation.js 行2073）、(2) Module Federation（共有モジュール解決）で失敗した時（resolveMatchedConfigs.js 行69, ConsumeSharedPlugin.js 行197）、(3) VirtualUrlPluginでのモジュール解決失敗時（VirtualUrlPlugin.js 行223）。

**通知の受信者**：Webpackビルドを実行した開発者。

**通知内容の概要**：「Module not found: {元のエラーメッセージ}」の基本メッセージに加え、Node.jsコアモジュールの場合は「BREAKING CHANGE: webpack < 5 used to include polyfills...」という移行ガイダンスと、resolve.fallbackの具体的な設定例が付加される。

**期待されるアクション**：開発者は、(1) 指定したモジュール名やパスのタイポを修正する、(2) 必要なパッケージをnpm/yarn installする、(3) Node.jsコアモジュールの場合はresolve.fallbackを設定してPolyfillパッケージをインストールする、(4) Polyfillが不要な場合はresolve.fallbackでfalseを設定する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

Compilationのモジュールファクトリ実行時にエラーが発生した場合、callbackの第1引数としてModuleNotFoundErrorが返される。このエラーはCompilation内部で処理され、Compilation.errorsに追加されるか、ビルド自体が失敗する。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

基本形:
```
Module not found: {err.toString()}
```

Node.jsコアモジュールの場合の追加メッセージ:
```
Module not found: Error: Can't resolve '{request}'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
	- add a fallback 'resolve.fallback: { "{request}": require.resolve("{alias}") }'
	- install '{dependency}'
If you don't want to include a polyfill, you can use an empty module like this:
	resolve.fallback: { "{request}": false }
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| module | エラーが発生したモジュール（null可） | コンストラクタ引数 | No |
| err | 元のエラーオブジェクト | resolverからのエラー | Yes |
| loc | 依存関係のソースコード位置情報 | 依存関係のlocプロパティ | Yes |
| name | エラー名称（固定値 "ModuleNotFoundError"） | クラス内で設定 | Yes |
| details | 元エラーのdetails | err.details | No |
| error | 元のエラーオブジェクト参照 | コンストラクタ引数 | Yes |
| request | 解決できなかったモジュール名 | err.messageからの正規表現抽出 | No |
| alias | Polyfillパッケージのパス | previouslyPolyfilledBuiltinModulesマップ | No |
| dependency | Polyfillパッケージ名 | aliasからのスラッシュ前部分 | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| モジュール解決 | Compilationのfactorize処理でエラー | モジュールが見つからない場合 | Compilation.js 行2073-2079 |
| 共有モジュール解決 | resolveMatchedConfigsでのresolve失敗 | 共有モジュールの解決に失敗した場合 | resolveMatchedConfigs.js 行69 |
| ConsumeSharedPlugin | 共有モジュール消費時のresolve失敗 | fallback解決に失敗した場合 | ConsumeSharedPlugin.js 行197 |
| VirtualUrlPlugin | 仮想URLのモジュール解決失敗 | モジュールが見つからない場合 | VirtualUrlPlugin.js 行223 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| モジュール解決成功 | resolverがモジュールを正常に解決できた場合 |
| stats.errors=false | Stats出力でエラー表示が抑制される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[import/require文の解析] --> B[resolverにモジュール解決を依頼]
    B --> C{解決成功?}
    C -->|Yes| D[正常処理継続]
    C -->|No| E[ModuleNotFoundError生成]
    E --> F{Node.jsコアモジュール?}
    F -->|Yes| G[BREAKING CHANGEメッセージ追加]
    F -->|No| H[基本エラーメッセージのみ]
    G --> I[Polyfillガイダンス追加]
    I --> J[callback error として返却]
    H --> J
    J --> K[Compilation.errors に追加]
    K --> L[Stats出力]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Node.jsコアモジュール不在 | crypto, buffer等のコアモジュールがresolveできない | resolve.fallbackの設定とPolyfillパッケージのインストール |
| サードパーティモジュール不在 | npm installされていないパッケージの参照 | npm/yarn installでパッケージをインストール |
| パスの誤り | 相対パスやエイリアスの設定ミス | import/require文のパスを修正 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

エラーメッセージにモジュールパスやプロジェクト構造が含まれるため、公開ログでの情報漏洩に注意。

## 備考

- `previouslyPolyfilledBuiltinModules` マップ（行13-42）には、Webpack 4以前で自動Polyfillされていた31個のNode.jsコアモジュールとその対応Polyfillパッケージが定義されている。
- このマップは「TODO remove in webpack 6」とコメントされており（行53）、Webpack 6で削除される予定。
- `makeSerializable` で登録されていないため、キャッシュのシリアライズ/デシリアライズでは基底クラスの機能のみ使用される。
- moduleパラメータにnullを渡すことが許容されている（Module Federationの場合など）。

---

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

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

### 推奨読解順序

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

ModuleNotFoundErrorのメッセージ構築ロジックとPolyfillマップを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ModuleNotFoundError.js | `lib/ModuleNotFoundError.js` | previouslyPolyfilledBuiltinModulesマップ（行13-42）、コンストラクタのメッセージ構築ロジック（行50-87） |

**読解のコツ**: コンストラクタ（行50-87）では、まず基本メッセージを構築した後、正規表現 `/Can't resolve '([^']+)'/` でモジュール名を抽出し、それが `previouslyPolyfilledBuiltinModules` に含まれるかチェックする。含まれる場合、BREAKING CHANGEメッセージとPolyfill設定方法のガイダンスが追加される。

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

Compilationのモジュールファクトリ実行でのエラーハンドリングを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Compilation.js | `lib/Compilation.js` | factorize処理のエラーコールバック（行2072-2079） |

**主要処理フロー**:
1. **行2072**: `if (err)` でresolverエラーの存在を確認
2. **行2073**: `new ModuleNotFoundError(originModule, err, dependencies.map(d => d.loc).find(Boolean))` でインスタンス生成
3. **行2079**: `callback(notFoundError, ...)` でエラーを上位に返却

#### Step 3: 他の生成元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | resolveMatchedConfigs.js | `lib/sharing/resolveMatchedConfigs.js` | Module Federation共有モジュール解決失敗時（行69） |
| 3-2 | ConsumeSharedPlugin.js | `lib/sharing/ConsumeSharedPlugin.js` | 共有モジュール消費時の解決失敗（行197） |
| 3-3 | VirtualUrlPlugin.js | `lib/schemes/VirtualUrlPlugin.js` | 仮想URL解決失敗時（行223） |

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

```
Compilation._factorizeModule()
    │
    ├─ moduleFactory.create()
    │      └─ resolver.resolve() 失敗
    │             └─ err (Error: Can't resolve '...')
    │
    └─ new ModuleNotFoundError(originModule, err, loc)  [Compilation.js 行2073]
           ├─ message = "Module not found: " + err.toString()  [行51]
           ├─ match = /Can't resolve '([^']+)'/.exec(err.message)  [行54]
           ├─ alias = previouslyPolyfilledBuiltinModules[request]  [行57-60]
           └─ (alias存在時) BREAKING CHANGE ガイダンス追加  [行64-76]

resolveMatchedConfigs()                          [resolveMatchedConfigs.js]
    └─ new ModuleNotFoundError(null, err, {})    [行69]

ConsumeSharedPlugin                              [ConsumeSharedPlugin.js]
    └─ new ModuleNotFoundError(null, err, {})    [行197]

VirtualUrlPlugin                                 [VirtualUrlPlugin.js]
    └─ throw new ModuleNotFoundError(...)        [行223]
```

### データフロー図

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

resolver.resolve()        ───> エラー発生                      ───> err
  モジュール解決失敗              Can't resolve 'xxx'                 │
                                                                     v
err.message               ───> 正規表現でモジュール名抽出      ───> request
                                /Can't resolve '([^']+)'/            │
                                                                     v
previouslyPolyfilled-     ───> マップ参照                      ───> alias/dependency
BuiltinModules                  (Node.jsコアモジュール判定)          │
                                                                     v
                           ───> メッセージ構築                  ───> ModuleNotFoundError
                                基本メッセージ                       │
                                + BREAKING CHANGE (該当時)           v
                                + Polyfillガイダンス (該当時)   Compilation.errors[]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ModuleNotFoundError.js | `lib/ModuleNotFoundError.js` | ソース | モジュール未検出エラークラス定義、Polyfillマップ |
| WebpackError.js | `lib/WebpackError.js` | ソース | 基底エラー/警告クラス |
| Compilation.js | `lib/Compilation.js` | ソース | モジュールファクトリ実行とエラーハンドリング |
| resolveMatchedConfigs.js | `lib/sharing/resolveMatchedConfigs.js` | ソース | Module Federation共有モジュール解決 |
| ConsumeSharedPlugin.js | `lib/sharing/ConsumeSharedPlugin.js` | ソース | Module Federation消費側プラグイン |
| VirtualUrlPlugin.js | `lib/schemes/VirtualUrlPlugin.js` | ソース | 仮想URLスキームプラグイン |
