# 機能設計書 15-@babel/preset-env

## 概要

本ドキュメントは、Babelの@babel/preset-envパッケージの機能設計を記述する。@babel/preset-envは、ターゲット環境に基づいて必要なBabelプラグインを自動的に選択するスマートプリセットである。

### 本機能の処理概要

@babel/preset-envは、指定されたターゲットブラウザやNode.jsバージョンに基づいて、必要最小限のBabelプラグインセットを自動決定し、効率的なコード変換を実現する。

**業務上の目的・背景**：従来、開発者はES6+の各機能に対応するプラグインを手動で選択・設定する必要があった。しかし、ターゲット環境によって必要なプラグインは異なり、この作業は複雑で間違いが起きやすかった。@babel/preset-envは、ターゲット環境を指定するだけで適切なプラグインを自動選択し、不要な変換を避けることでバンドルサイズの最適化とビルド時間の短縮を実現する。

**機能の利用シーン**：フロントエンド・バックエンドアプリケーションのビルド設定、ライブラリの配布用コンパイル、レガシーブラウザサポート要件のあるプロジェクトなど、ほぼ全てのBabelプロジェクトで利用される。

**主要な処理内容**：
1. ターゲット環境の解析（browserslist、直接指定など）
2. @babel/compat-dataを参照して必要なプラグインを判定
3. include/excludeオプションによるプラグインの追加/除外
4. モジュール変換の制御（commonjs, amd, umd, systemjs, false）
5. ポリフィルの注入制御（useBuiltIns: usage/entry）
6. バグ修正プラグインの適用

**関連システム・外部連携**：@babel/compat-data（互換性データ）、@babel/helper-compilation-targets（ターゲット解析）、browserslist（ブラウザクエリ解析）、babel-plugin-polyfill-corejs3（ポリフィル注入）と連携。

**権限による制御**：本機能に権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | Babelトランスフォームデモ | 補助機能 | ES2015構文の変換に使用（presetsに"es2015"を指定） |
| 2 | インラインスクリプトタグデモ | 補助機能 | デフォルトプリセットとしてES2015+構文を変換 |
| 3 | 外部スクリプトタグデモ | 補助機能 | デフォルトプリセットとしてES2015+構文を変換 |
| 4 | カスタムスクリプトタグデモ | 補助機能 | デフォルトプリセットとしてES2015+構文を変換 |

## 機能種別

プリセット / コード変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| targets | string/object | No | ターゲット環境 | browserslist形式または環境オブジェクト |
| include | string[] | No | 常に含めるプラグイン | プラグイン名の配列 |
| exclude | string[] | No | 常に除外するプラグイン | プラグイン名の配列 |
| modules | string/false | No | モジュール変換形式 | "amd", "umd", "systemjs", "commonjs", "auto", false |
| useBuiltIns | string/false | No | ポリフィル注入方式 | "usage", "entry", false |
| corejs | string/object | No | core-jsバージョン | "3", "3.x", { version: "3.x", proposals: true } |
| forceAllTransforms | boolean | No | 全変換を強制 | デフォルト: false |
| configPath | string | No | browserslist設定のパス | ディレクトリパス |
| ignoreBrowserslistConfig | boolean | No | browserslist設定を無視 | デフォルト: false |
| shippedProposals | boolean | No | 出荷済み提案を含める | デフォルト: false |
| debug | boolean | No | デバッグ出力 | デフォルト: false |

### 入力データソース

- Babel設定ファイル（babel.config.js, .babelrc等）
- API呼び出しのオプション
- browserslist設定（package.json, .browserslistrc等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| plugins | array | 適用するプラグインの配列 |

### 出力先

Babelコア(@babel/core)に対してプラグイン配列を返却する。

## 処理フロー

### 処理シーケンス

```
1. オプションの正規化
   └─ normalizeOptions: デフォルト値設定、バリデーション

2. ターゲット環境の解析
   └─ getTargets: browserslistまたは直接指定からターゲットを取得
   └─ api.targets(): @babel/coreからのターゲット情報を取得

3. プラグインリストの決定
   └─ @babel/compat-dataからプラグイン互換性データを取得
   └─ filterItems: ターゲットに必要なプラグインをフィルタ
   └─ include/excludeを適用
   └─ addProposalSyntaxPlugins: 提案構文プラグインを追加
   └─ removeUnsupportedItems: 非サポートプラグインを除去
   └─ removeUnnecessaryItems: 重複プラグインを除去

4. モジュール変換の設定
   └─ modules: "auto"の場合はcallerからESMサポートを判定
   └─ 適切なモジュール変換プラグインを追加

5. ポリフィルの設定
   └─ useBuiltIns有効時: babel-plugin-polyfill-corejs3を追加

6. プラグイン配列の構築と返却
```

### フローチャート

```mermaid
flowchart TD
    A[preset-env呼び出し] --> B[normalizeOptions]
    B --> C{targets指定?}
    C -->|Yes| D[getTargets]
    C -->|No| E[api.targets使用]
    D --> F[compat-data取得]
    E --> F
    F --> G[filterItems]
    G --> H[include適用]
    H --> I[exclude適用]
    I --> J{shippedProposals?}
    J -->|Yes| K[proposalPlugins追加]
    J -->|No| L[removeUnnecessaryItems]
    K --> L
    L --> M{useBuiltIns?}
    M -->|Yes| N[polyfillプラグイン追加]
    M -->|No| O[プラグイン配列返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | modules: auto | caller.supportsStaticESMがtrueならモジュール変換しない | modules: "auto"時 |
| BR-02 | loose/spec廃止 | Babel 8でloose/specオプションは削除、assumptionsを使用 | 常時 |
| BR-03 | ターゲット優先度 | esmodulesとbrowsersが両方指定された場合、browsersは無視 | 両方指定時 |
| BR-04 | バグ修正プラグイン | shippedProposals有効時はバグ修正プラグインも含める | shippedProposals: true |
| BR-05 | デバッグ出力 | debug: trueでターゲットとプラグイン一覧を出力 | debug: true |

### 計算ロジック

プラグイン必要性判定:
```javascript
// @babel/helper-compilation-targetsのfilterItemsを使用
const pluginNames = filterItems(
  compatData,         // プラグインの互換性データ
  include.plugins,    // 常に含めるプラグイン
  exclude.plugins,    // 常に除外するプラグイン
  transformTargets,   // ターゲット環境
  specialModulesPluginNames,  // モジュール変換プラグイン
  undefined,
  pluginSyntaxMap     // 構文プラグインマッピング
);

// 各プラグインについて:
// ターゲットの全環境でサポートされている → 除外
// 1つでもサポートされていない環境がある → 含める
```

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | loose/specオプション使用 | assumptionsに移行 |
| - | Error | 無効なターゲット指定 | browserslist形式で指定 |
| - | Warning | esmodulesとbrowsers両方指定 | どちらか一方を使用 |

### リトライ仕様

本機能にリトライ処理は存在しない。

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

本機能はトランザクション処理を行わない。

## パフォーマンス要件

- プリセット初期化は1回のみ（キャッシュされる）
- プラグインフィルタリングはO(n)（プラグイン数に比例）
- compat-dataはJSONファイルとして即座に読み込み

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

- 外部browserslist設定を読み込むため、信頼できる設定ファイルのみ使用
- configPathはファイルシステムアクセスを伴う

## 備考

- Babel 7.13.0以降ではtop-level targetsが優先される
- 動的import変換はmodules: "auto"と組み合わせて使用
- export-namespace-fromは特別扱いで強制include

---

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

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

### 推奨読解順序

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

まず、プリセットのメイン処理を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-preset-env/src/index.ts` | プリセットのメイン実装 |

**読解のコツ**:
- **195-337行目**: declarePreset関数。プリセットのメイン処理
- **200-206行目**: loose/specオプションの廃止エラー
- **208-221行目**: normalizeOptionsでオプション正規化
- **223-244行目**: ターゲット環境の取得ロジック
- **278-293行目**: filterItemsでプラグインフィルタリング
- **313-317行目**: プラグイン配列の構築
- **319-334行目**: debugモード時のコンソール出力

#### Step 2: オプション正規化を理解する

オプションの検証と正規化処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | normalize-options.ts | `packages/babel-preset-env/src/normalize-options.ts` | オプション正規化 |

#### Step 3: フィルタリングロジックを理解する

プラグインの選択/除外ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | filter-items.ts | `packages/babel-preset-env/src/filter-items.ts` | フィルタリング処理 |

**主要処理フロー**:
- addProposalSyntaxPlugins: 提案構文プラグインの追加
- removeUnnecessaryItems: 重複プラグインの除去
- removeUnsupportedItems: 非サポートプラグインの除去

#### Step 4: 互換性データを理解する

@babel/compat-dataとの連携を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | plugins-compat-data.ts | `packages/babel-preset-env/src/plugins-compat-data.ts` | compat-dataのインポート |
| 4-2 | available-plugins.ts | `packages/babel-preset-env/src/available-plugins.ts` | 利用可能プラグイン定義 |

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

```
@babel/preset-env
    │
    ├─ declarePreset (@babel/helper-plugin-utils)
    │
    ├─ normalizeOptions
    │      └─ オプションの検証と正規化
    │
    ├─ getTargets (@babel/helper-compilation-targets)
    │      └─ browserslist解析
    │
    ├─ filterItems (@babel/helper-compilation-targets)
    │      └─ @babel/compat-data/plugins
    │
    ├─ addProposalSyntaxPlugins (filter-items.ts)
    ├─ removeUnsupportedItems (filter-items.ts)
    ├─ removeUnnecessaryItems (filter-items.ts)
    │
    ├─ getPlugin (available-plugins.ts)
    │      └─ 各変換プラグインを取得
    │
    └─ pluginCoreJS3 (babel-plugin-polyfill-corejs3)
           └─ ポリフィル注入
```

### データフロー図

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

targets ─────────────> getTargets ──────────────────┐
                                                    │
browserslist設定 ────> browserslist解析 ────────────┤
                                                    │
@babel/compat-data ──> プラグイン互換性データ ───────┼──> filterItems ──> plugins[]
                                                    │         │
include/exclude ─────> Set化 ─────────────────────────────────┘
                                                              │
modules ─────────────> モジュールプラグイン選択 ──────────────────┤
                                                              │
useBuiltIns/corejs ──> polyfillプラグイン設定 ───────────────────┘
                                                              │
                                                    { plugins: [...] }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-preset-env/src/index.ts` | ソース | プリセットメイン実装 |
| normalize-options.ts | `packages/babel-preset-env/src/normalize-options.ts` | ソース | オプション正規化 |
| filter-items.ts | `packages/babel-preset-env/src/filter-items.ts` | ソース | プラグインフィルタリング |
| plugins-compat-data.ts | `packages/babel-preset-env/src/plugins-compat-data.ts` | ソース | 互換性データインポート |
| available-plugins.ts | `packages/babel-preset-env/src/available-plugins.ts` | ソース | プラグイン定義 |
| module-transformations.ts | `packages/babel-preset-env/src/module-transformations.ts` | ソース | モジュール変換マッピング |
| shipped-proposals.ts | `packages/babel-preset-env/src/shipped-proposals.ts` | ソース | 出荷済み提案プラグイン |
| debug.ts | `packages/babel-preset-env/src/debug.ts` | ソース | デバッグ出力 |
| types.d.ts | `packages/babel-preset-env/src/types.d.ts` | 型定義 | TypeScript型定義 |
| package.json | `packages/babel-preset-env/package.json` | 設定 | パッケージ設定 |
