# 機能設計書 40-SharePlugin

## 概要

本ドキュメントは、webpackのModule Federationにおける共有依存パッケージ管理機能（SharePlugin）について記述する。SharePluginは複数のFederationアプリケーション間で依存パッケージを共有する仕組みを提供し、ConsumeSharedPluginとProvideSharedPluginを統合的に管理する。

### 本機能の処理概要

SharePluginは、Module Federationの共有依存パッケージ管理のオーケストレーションプラグインである。shared設定で指定されたパッケージについて、提供側（ProvideSharedPlugin）と消費側（ConsumeSharedPlugin）の両方の設定を自動生成し、適用する。

**業務上の目的・背景**：マイクロフロントエンドにおいて、React、lodash等の共通ライブラリが各アプリケーションで個別にバンドルされると、メモリ使用量の増大やバージョン不整合が生じる。SharePluginにより、複数アプリケーションが同一バージョンのライブラリを共有し、重複読み込みを回避できる。singleton制約やバージョン要件の管理も行われる。

**機能の利用シーン**：
- 複数のModule Federationアプリケーション間でReact等のUI ライブラリを共有する場合
- バージョン制約付きでの依存共有（strictVersion, requiredVersion）
- 即座読み込み（eager）によるSSR対応

**主要な処理内容**：
1. shared設定の解析とconsumes/providesオプションへの変換
2. ConsumeSharedPlugin適用（共有モジュールの消費側管理）
3. ProvideSharedPlugin適用（共有モジュールの提供側管理）
4. バージョン解決・互換性チェック
5. 共有スコープの管理

**関連システム・外部連携**：package.jsonのversionフィールドを参照してバージョン情報を取得する。semverによるバージョン範囲解析・比較を行う。

**権限による制御**：特になし。shared設定により共有対象パッケージを制御する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 19 | App (Host) (module-federation) | 補助機能 | react,date-fns等の依存パッケージをリモート間で共有 |
| 20 | MFE-B (Remote) (module-federation) | 補助機能 | reactをsingleton制約で共有 |
| 21 | MFE-C (Remote) (module-federation) | 補助機能 | reactをsingleton制約で共有 |

## 機能種別

プラグインオーケストレーション / 依存管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| shared | object/array | Yes | 共有するパッケージの定義 | parseOptionsで解析 |
| shareScope | string | No | 共有スコープ名 | - |

#### shared個別設定（SharedConfig）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| import | string \| false | No | パッケージのインポート先（falseで消費のみ） | - |
| shareKey | string | No | 共有キー名（デフォルト: パッケージ名） | - |
| shareScope | string | No | 共有スコープ名 | - |
| requiredVersion | string | No | 必要バージョン範囲（semver） | isRequiredVersionで検証 |
| strictVersion | boolean | No | バージョン厳密チェック | - |
| singleton | boolean | No | シングルトン制約（1バージョンのみ許可） | - |
| packageName | string | No | パッケージ名 | - |
| eager | boolean | No | 即座読み込み（遅延なし） | - |
| version | string | No | 提供するバージョン | - |

### 入力データソース

- ModuleFederationPluginから渡されるshared設定
- package.jsonのversionフィールド（ProvideSharedPlugin側）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ConsumeSharedModule | Module | 共有モジュールの消費側モジュール |
| ProvideSharedModule | Module | 共有モジュールの提供側モジュール |
| ConsumeSharedRuntimeModule | RuntimeModule | 共有モジュール消費のランタイムコード |
| shareScope初期化コード | string | 共有スコープの初期化ランタイムコード |

### 出力先

バンドルファイル内のモジュール・ランタイムコードとして出力。

## 処理フロー

### 処理シーケンス

```
SharePlugin:
1. shared設定解析
   ├─ 文字列の場合: 同名パッケージのimportとして扱う
   ├─ バージョン文字列の場合: importはキー名、requiredVersionは値
   └─ オブジェクトの場合: そのまま使用
2. consumes設定生成
   └─ 各sharedからConsumeSharedPluginのconsumes設定を構築
3. provides設定生成
   └─ import !== falseのsharedからProvideSharedPluginのprovides設定を構築
4. ConsumeSharedPlugin適用
   └─ shareScope + consumesで消費側プラグインを適用
5. ProvideSharedPlugin適用
   └─ shareScope + providesで提供側プラグインを適用

ConsumeSharedPlugin:
1. consumes設定の解析・正規化
2. package.jsonからrequiredVersion自動検出
3. ConsumeSharedModuleの生成
4. ConsumeSharedRuntimeModuleの追加

ProvideSharedPlugin:
1. provides設定の解析・正規化
2. package.jsonからversion自動検出
3. ProvideSharedDependencyの追加
4. ProvideSharedModuleの生成
```

### フローチャート

```mermaid
flowchart TD
    A[SharePlugin.constructor] --> B[parseOptions: shared解析]
    B --> C[consumes設定生成]
    B --> D[provides設定生成]
    C --> E[ConsumeSharedPlugin適用]
    D --> F[ProvideSharedPlugin適用]

    E --> G[consumes解析・正規化]
    G --> H[package.json requiredVersion検出]
    H --> I[ConsumeSharedModule生成]
    I --> J[ConsumeSharedRuntimeModule追加]

    F --> K[provides解析・正規化]
    K --> L[package.json version検出]
    L --> M[ProvideSharedDependency追加]
    M --> N[ProvideSharedModule生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | import推定 | shared設定が文字列で、キー名と一致するか非バージョン文字列の場合はimportとして扱う | SharePluginコンストラクタ |
| BR-02 | バージョン推定 | shared設定が文字列でisRequiredVersionがtrueの場合、requiredVersionとして扱う | SharePluginコンストラクタ |
| BR-03 | provides除外 | import === falseのshared設定はprovides生成対象から除外 | provides生成時 |
| BR-04 | デフォルトshareKey | shareKey未指定時はパッケージ名をshareKeyとして使用 | consumes/provides生成時 |
| BR-05 | singleton制約 | singleton=trueの場合、共有スコープ内で1バージョンのみ許可 | ランタイム時 |
| BR-06 | strictVersion | strictVersion=trueの場合、requiredVersionに合致しないバージョンはエラー | ランタイム時 |
| BR-07 | eager読み込み | eager=trueの場合、共有モジュールを同期的に即座読み込み | ランタイム時 |
| BR-08 | バージョン自動検出 | requiredVersion/version未指定時、package.jsonのversionフィールドから自動取得 | ConsumeSharedPlugin / ProvideSharedPlugin |

### 計算ロジック

consumes変換: sharedOptionsの各エントリ[key, options]に対して、{[key]: {import, shareKey, shareScope, requiredVersion, strictVersion, singleton, packageName, eager}}を生成する。shareKeyのデフォルトはkey名。

provides変換: import !== falseのsharedOptionsエントリに対して、{[options.import || key]: {shareKey, shareScope, version, eager}}を生成する。

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | shared設定に予期しない配列が含まれる | "Unexpected array in shared"エラースロー |
| - | バリデーションエラー | consumesまたはprovides設定のスキーマ違反 | createSchemaValidationでエラー出力 |
| - | WebpackError | 提供モジュールが見つからない場合 | ProvideSharedPluginでWebpackErrorを生成 |
| - | ModuleNotFoundError | consumeのimportモジュールが見つからない場合 | ConsumeSharedPluginでModuleNotFoundError |
| - | ランタイムエラー | バージョン不一致（strictVersion=true時） | ランタイムでエラースロー |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 共有モジュールの重複バンドルを回避しバンドルサイズを削減
- eager=falseの場合は遅延読み込みで初期ロード時間を短縮
- ProvideSharedPluginのソートによる決定的な処理順序保証

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

- 共有スコープを通じたモジュール注入の可能性に注意
- requiredVersionの適切な設定によるバージョン互換性の保証

## 備考

- SharePluginはConsumeSharedPluginとProvideSharedPluginのオーケストレーター
- semverライブラリ（lib/util/semver.js）によるバージョン範囲の解析・比較
- resolveMatchedConfigs（lib/sharing/resolveMatchedConfigs.js）による設定解決

---

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

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

### 推奨読解順序

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

SharePluginの設定構造と変換ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SharePlugin.js | `lib/sharing/SharePlugin.js` | 13-16行目: 型定義のインポート（ConsumesConfig, ProvidesConfig, SharePluginOptions, SharedConfig） |
| 1-2 | ConsumeSharedPlugin.js | `lib/sharing/ConsumeSharedPlugin.js` | 57-88行目: ConsumeOptionsの構造（import, shareScope, shareKey, requiredVersion, strictVersion, singleton, packageName, eager） |
| 1-3 | ProvideSharedPlugin.js | `lib/sharing/ProvideSharedPlugin.js` | 30-35行目: ProvideOptionsの構造（shareKey, shareScope, version, eager） |

**読解のコツ**: SharePluginはシンプルなオーケストレーターであり、コンストラクタでshared設定をconsumes/provides形式に変換し、apply()でConsumeSharedPlugin/ProvideSharedPluginに委譲する。変換ロジックの理解が重要。

#### Step 2: SharePluginのオーケストレーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SharePlugin.js | `lib/sharing/SharePlugin.js` | 23-44行目: コンストラクタでshared設定の解析 |
| 2-2 | SharePlugin.js | `lib/sharing/SharePlugin.js` | 46-57行目: consumes設定の生成 |
| 2-3 | SharePlugin.js | `lib/sharing/SharePlugin.js` | 59-68行目: provides設定の生成（import !== falseのみ） |
| 2-4 | SharePlugin.js | `lib/sharing/SharePlugin.js` | 79-88行目: apply()でConsumeSharedPlugin/ProvideSharedPluginを適用 |

**主要処理フロー**:
1. **25-44行目**: parseOptionsでshared設定を[key, SharedConfig]配列に正規化
2. **28-40行目**: 文字列型の判定 - isRequiredVersionでバージョン文字列かを判別
3. **46-57行目**: consumesマッピング - import, shareKey, shareScope, requiredVersion, strictVersion, singleton, packageName, eager
4. **59-68行目**: providesマッピング - shareKey, shareScope, version, eager
5. **80-83行目**: ConsumeSharedPlugin(shareScope, consumes)を適用
6. **84-87行目**: ProvideSharedPlugin(shareScope, provides)を適用

#### Step 3: ConsumeSharedPlugin（消費側）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ConsumeSharedPlugin.js | `lib/sharing/ConsumeSharedPlugin.js` | 48-100行目: コンストラクタでconsumes設定の正規化 |

**主要処理フロー**:
- **58-88行目**: parseOptionsでconsumes設定を[key, ConsumeOptions]配列に正規化
- **82行目**: parseRange(item.requiredVersion)でsemverバージョン範囲を解析
- apply()でcompilation.hooks.compilationに各種フック登録

#### Step 4: ProvideSharedPlugin（提供側）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ProvideSharedPlugin.js | `lib/sharing/ProvideSharedPlugin.js` | 41-100行目: コンストラクタとapply()の入口 |

**主要処理フロー**:
- **49-75行目**: parseOptionsでprovides設定を[key, ProvideOptions]配列に正規化
- **71-75行目**: provides配列をソートし決定的な処理順序を保証
- **83-100行目**: apply()でcompilationData(WeakMap)を初期化しresolvedProvideMapを構築

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

```
SharePlugin.constructor(options)
    |
    +-- parseOptions(options.shared) → sharedOptions
    |
    +-- sharedOptions.map() → consumes配列
    +-- sharedOptions.filter().map() → provides配列
    |
    +-- SharePlugin.apply(compiler)
           |
           +-- ConsumeSharedPlugin({ shareScope, consumes }).apply(compiler)
           |      +-- parseOptions(consumes) → _consumes
           |      +-- compilation.hooks.compilation.tap
           |      |      +-- resolveMatchedConfigs
           |      |      +-- ConsumeSharedModule生成
           |      +-- compilation.hooks.additionalTreeRuntimeRequirements.tap
           |             +-- ConsumeSharedRuntimeModule追加
           |
           +-- ProvideSharedPlugin({ shareScope, provides }).apply(compiler)
                  +-- parseOptions(provides) → _provides
                  +-- compiler.hooks.compilation.tap
                  |      +-- resolvedProvideMap構築
                  |      +-- ProvideSharedDependency追加
                  +-- compiler.hooks.finishMake.tapPromise
                         +-- ProvideSharedModule生成
```

### データフロー図

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

shared設定 ──────────────> SharePlugin                   ──> consumes設定
  {react: {singleton:true}}     |                           provides設定
                                v
consumes設定 ────────────> ConsumeSharedPlugin           ──> ConsumeSharedModule
  + package.json                |                           ConsumeSharedRuntimeModule
                                +-> バージョン解析
                                +-> フォールバック解決
                                v
provides設定 ────────────> ProvideSharedPlugin           ──> ProvideSharedModule
  + package.json                |                           ProvideSharedDependency
                                +-> バージョン検出
                                +-> 提供モジュール登録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SharePlugin.js | `lib/sharing/SharePlugin.js` | ソース | 共有パッケージ管理のオーケストレーター（本機能の主要ファイル） |
| ConsumeSharedPlugin.js | `lib/sharing/ConsumeSharedPlugin.js` | ソース | 共有モジュールの消費側管理 |
| ProvideSharedPlugin.js | `lib/sharing/ProvideSharedPlugin.js` | ソース | 共有モジュールの提供側管理 |
| ConsumeSharedModule.js | `lib/sharing/ConsumeSharedModule.js` | ソース | 消費側モジュール定義 |
| ConsumeSharedRuntimeModule.js | `lib/sharing/ConsumeSharedRuntimeModule.js` | ソース | 消費側ランタイムコード生成 |
| ConsumeSharedFallbackDependency.js | `lib/sharing/ConsumeSharedFallbackDependency.js` | ソース | 消費側フォールバック依存 |
| ProvideSharedDependency.js | `lib/sharing/ProvideSharedDependency.js` | ソース | 提供側依存 |
| ProvideSharedModuleFactory.js | `lib/sharing/ProvideSharedModuleFactory.js` | ソース | 提供側モジュールファクトリ |
| ProvideForSharedDependency.js | `lib/sharing/ProvideForSharedDependency.js` | ソース | 提供用依存 |
| resolveMatchedConfigs.js | `lib/sharing/resolveMatchedConfigs.js` | ソース | 設定マッチング解決 |
| utils.js | `lib/sharing/utils.js` | ソース | ユーティリティ（isRequiredVersion, getDescriptionFile等） |
| options.js | `lib/container/options.js` | ソース | parseOptionsユーティリティ |
