# 機能設計書 58-ProvidePlugin

## 概要

本ドキュメントは、webpackにおけるProvidePlugin機能の設計仕様を記述する。指定した識別子がソースコード内で使用された場合、自動的に対応するモジュールをインポートし、明示的なimport/require文なしで利用可能にする機能である。

### 本機能の処理概要

**業務上の目的・背景**：jQueryやlodash等のライブラリを多数のファイルで使用する場合、全ファイルにimport文を記述するのは冗長である。また、レガシーコードの移行時にグローバル変数への依存を解消したい場合もある。ProvidePluginは、指定した識別子（例: `$`、`_`）がコード内で検出された際に、自動的に対応モジュールのimport文を注入する。これにより、コードの簡潔性を保ちつつ、モジュールバンドリングの利点を維持できる。

**機能の利用シーン**：jQueryの`$`グローバル変数の自動提供、lodashの`_`自動提供、Node.jsのBuffer/processの自動ポリフィル、レガシーコードのモジュール化に利用される。

**主要な処理内容**：
1. 識別子→モジュールパスのマッピングを受け取る
2. JavaScriptパーサのexpressionフックとcallフックにタップする
3. ドット区切りの識別子（例: `React.Component`）をサポートするためにcanRenameフックも登録する
4. 識別子が検出されるとProvidedDependencyを生成してモジュールに追加する
5. ProvidedDependencyがモジュールの解決・読み込みをトリガーする

**関連システム・外部連携**：NormalModuleFactoryを通じてProvidedDependencyの解決を行う。ConstDependencyとProvidedDependencyの2種類の依存オブジェクトを使用する。

**権限による制御**：特になし。webpack設定のpluginsで設定する。

## 関連画面

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

## 機能種別

コード変換処理 / 依存関係自動注入

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| definitions | Record<string, string \| string[]> | Yes | 識別子→モジュールパスのマッピング | - |

### 入力データソース

- webpack設定: `new ProvidePlugin({ $: 'jquery', _: 'lodash' })`
- 配列形式: `{ React: ['react', 'default'] }` でモジュール+エクスポート名を指定可能

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ProvidedDependency | Dependency | 自動提供モジュールの依存オブジェクト |
| ConstDependency | Dependency | 識別子置換用の定数依存オブジェクト |

### 出力先

モジュールの依存関係に追加され、モジュール解決時に対応モジュールが自動的にバンドルに含まれる

## 処理フロー

### 処理シーケンス

```
1. ProvidePlugin.apply() → compiler.hooks.compilation にタップ
   └─ ConstDependency.Template と ProvidedDependency.Template を登録
2. normalModuleFactory に ProvidedDependency のファクトリを登録
   └─ ProvidedDependencyの解決をNormalModuleFactoryに委譲
3. parser フックの登録
   a. ドット区切り識別子の場合、canRenameフックでプロパティアクセスを許可
   b. expressionフック: 識別子のアクセス時にProvidedDependencyを追加
   c. callフック: 識別子の関数呼び出し時にProvidedDependencyを追加
4. モジュール解析時に識別子が検出されると依存関係が追加される
5. モジュール解決・バンドル時に対応モジュールが自動的に含まれる
```

### フローチャート

```mermaid
flowchart TD
    A[ProvidePlugin.apply] --> B[ConstDependency/ProvidedDependencyテンプレート登録]
    B --> C[NormalModuleFactoryにファクトリ登録]
    C --> D[パーサフック登録]
    D --> E{識別子にドットあり?}
    E -->|Yes| F[canRenameフック登録]
    E -->|No| G[expressionフック登録]
    F --> G
    G --> H[callフック登録]
    H --> I[モジュール解析時]
    I --> J{識別子検出?}
    J -->|Yes| K[ProvidedDependency生成]
    K --> L[module.addDependency]
    L --> M[NormalModuleFactoryで解決]
    J -->|No| N[スキップ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-58-01 | ドット区切りサポート | "React.Component"等のネスト識別子をサポートし、canRenameフックで各レベルのアクセスを許可する | 識別子にドットが含まれる場合 |
| BR-58-02 | 名前置換 | ドット区切り識別子の場合、`__webpack_provided_{name}_dot_{prop}`形式の内部名に変換する | 識別子にドットが含まれる場合 |
| BR-58-03 | エクスポート指定 | 配列形式`[modulePath, ...exportNames]`でモジュール内の特定エクスポートを参照可能 | 定義値が配列の場合 |
| BR-58-04 | 全JSモジュールタイプ対応 | AUTO, DYNAMIC, ESMの全JavaScriptモジュールタイプに対してフックを登録する | 常時 |
| BR-58-05 | expressionとcallの両方 | 識別子へのアクセス（参照）と関数呼び出しの両方でProvidedDependencyを生成する | 常時 |

### 計算ロジック

識別子名の変換: ドット区切り識別子`name`に対して、`__webpack_provided_${name.replace(/\./g, "_dot_")}`の内部名を生成する。request配列の先頭がモジュールパス、残りがエクスポートパスとなる。

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

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

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能自体はエラーをスローしない | モジュール解決失敗時はNormalModuleFactoryレベルでエラー |

### リトライ仕様

該当なし。

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

該当なし（コンパイル時の同期的な変換処理）

## パフォーマンス要件

- パーサフックレベルの軽量な処理
- 定義数に比例してフック登録数が増加するが、通常の使用範囲では問題にならない

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

特になし。

## 備考

- ProvidePluginはDefinePluginとは異なり、値の置換ではなくモジュールの自動インポートを行う
- process, Buffer等のNode.jsグローバルのブラウザポリフィルに広く使用されている
- 全121行のコンパクトなプラグインである

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ProvidePlugin.js | `lib/ProvidePlugin.js` | プラグインの全体構造（121行の小規模プラグイン） |

**読解のコツ**: ProvidePluginは非常にコンパクトなプラグインであり、一度に全体を読み通すことが可能。ProvidedDependencyの役割を理解するのがポイント。

- **23行目**: PLUGIN_NAME = "ProvidePlugin"
- **29-31行目**: コンストラクタ - definitionsを保持

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

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

**主要処理フロー**:
1. **40行目**: `compiler.hooks.compilation`にタップ
2. **43-46行目**: ConstDependency.Templateを登録
3. **47-50行目**: ProvidedDependencyのファクトリをnormalModuleFactoryに登録
4. **51-54行目**: ProvidedDependency.Templateを登録
5. **60-66行目**: handler関数内でdefinitionsの各エントリを処理
6. **67-73行目**: ドット区切り識別子に対してcanRenameフックを登録
7. **75-88行目**: expressionフック - 識別子アクセス時にProvidedDependencyを追加
8. **90-104行目**: callフック - 関数呼び出し時にProvidedDependencyを追加（引数のwalkも実行）
9. **107-115行目**: AUTO, DYNAMIC, ESMの全モジュールタイプにhandlerを登録

#### Step 3: ProvidedDependencyの理解

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ProvidedDependency.js | `lib/dependencies/ProvidedDependency.js` | 自動提供モジュールの依存オブジェクト |

**主要処理フロー**:
- コンストラクタ: request（モジュールパス）、identifier（内部名）、ids（エクスポートパス）、range（置換範囲）を受け取る
- Template: コード生成時にrequire文を注入

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

```
ProvidePlugin.apply(compiler)
    │
    └─ compiler.hooks.compilation
           ├─ ConstDependency.Template 登録
           ├─ ProvidedDependency → normalModuleFactory ファクトリ登録
           ├─ ProvidedDependency.Template 登録
           └─ normalModuleFactory.hooks.parser
                  └─ handler(parser)
                         ├─ parser.hooks.canRename.for(name) ──▶ approve
                         ├─ parser.hooks.expression.for(name)
                         │      └─ new ProvidedDependency(request, id, ids, range)
                         │             └─ parser.state.module.addDependency()
                         └─ parser.hooks.call.for(name)
                                └─ new ProvidedDependency(request, id, ids, range)
                                       └─ parser.state.module.addDependency()
```

### データフロー図

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

definitions ───────────────▶ handler(parser)                      ProvidedDependency
  { "$": "jquery" }            ├─ expressionフック                   │
                                │    └─ ProvidedDependency生成      module.dependencies
                                └─ callフック                          │
                                     └─ ProvidedDependency生成      NormalModuleFactory
                                                                       │
                                                                    jqueryモジュール解決
                                                                       │
                                                                    バンドルに含まれる
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ProvidePlugin.js | `lib/ProvidePlugin.js` | ソース | 自動モジュール提供プラグイン本体（121行） |
| ProvidedDependency.js | `lib/dependencies/ProvidedDependency.js` | ソース | 自動提供モジュールの依存オブジェクト |
| ConstDependency.js | `lib/dependencies/ConstDependency.js` | ソース | 定数置換依存オブジェクト |
| JavascriptParserHelpers.js | `lib/javascript/JavascriptParserHelpers.js` | ソース | approve関数（canRenameフック用） |
| ModuleTypeConstants.js | `lib/ModuleTypeConstants.js` | ソース | JAVASCRIPT_MODULE_TYPE_AUTO/DYNAMIC/ESM定数 |
