# 機能設計書 57-next/image（Image）

## 概要

本ドキュメントは、Next.jsの`next/image`（`<Image>`コンポーネント）の機能設計を記述する。`<Image>`コンポーネントはHTML標準の`<img>`要素を拡張し、遅延読み込み、レスポンシブサイズ、プレースホルダー表示、フォーマット最適化をクライアントサイドで自動的に適用する画像最適化コンポーネントである。

### 本機能の処理概要

**業務上の目的・背景**：Webアプリケーションにおいて画像はページサイズの大部分を占め、Core Web Vitals（LCP, CLS）に直接影響する。適切な画像最適化（遅延読み込み、適切なサイズ指定、モダンフォーマット配信）はパフォーマンスとUXの向上に不可欠であるが、手動実装は煩雑でミスが発生しやすい。`<Image>`コンポーネントは、これらの最適化をフレームワークレベルで自動適用し、開発者の負担を軽減する。

**機能の利用シーン**：記事のヒーロー画像、商品画像ギャラリー、アバター画像、バナー画像など、アプリケーション内のあらゆる画像表示場面で使用される。

**主要な処理内容**：
1. getImgPropsによる画像属性の計算（src, srcSet, sizes, width, height）
2. ImageElementコンポーネントによるimg要素のレンダリング
3. handleLoadingによる画像読み込み完了後のブラーフェードアウト
4. ImagePreloadによる優先画像のpreload link/ReactDOM.preload
5. fill属性によるレスポンシブフィルモード
6. placeholder属性によるブラー/空プレースホルダー
7. priority属性による即時読み込み（fetchPriority: high）
8. Next.js Image Optimizerとの連携（_next/image API）

**関連システム・外部連携**：Image Optimizer（サーバーサイド）、ImageConfigContext（next.config.jsの画像設定）、カスタムloader関数。

**権限による制御**：特にロールや権限による制御は行われない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 全画面で利用可能な汎用画像コンポーネント |

## 機能種別

UIコンポーネント / 画像最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| src | string \| StaticImport | Yes | 画像ソース（URL、静的インポート） | 必須 |
| alt | string | Yes | 代替テキスト | 必須（開発モードで警告） |
| width | number | Conditional | 画像の幅（fillでない場合必須） | 正の整数 |
| height | number | Conditional | 画像の高さ（fillでない場合必須） | 正の整数 |
| fill | boolean | No | 親要素を満たすレスポンシブモード | boolean |
| loader | ImageLoader | No | カスタム画像URLローダー関数 | 関数型 |
| quality | number | No | 画像品質（1-100） | 1-100の整数 |
| priority | boolean | No | 優先読み込み（LCP向け） | boolean |
| loading | 'lazy' \| 'eager' | No | 読み込み戦略（デフォルト: lazy） | - |
| placeholder | 'blur' \| 'empty' \| string | No | プレースホルダー種別 | - |
| blurDataURL | string | Conditional | ブラープレースホルダーのBase64データURL | placeholder='blur'時に静的画像以外で必須 |
| sizes | string | No | レスポンシブサイズヒント | - |
| unoptimized | boolean | No | 最適化を無効にするか | boolean |
| onLoad | function | No | 画像読み込み完了コールバック | 関数型 |
| onError | function | No | 画像読み込みエラーコールバック | 関数型 |

### 入力データソース

- コンポーネントProps経由でのユーザー指定値
- ImageConfigContext（next.config.jsの images 設定）
- configEnv（__NEXT_IMAGE_OPTS ビルド時注入設定）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| img要素 | React.ReactElement | 最適化されたimg要素 |
| preload link | React.ReactElement \| null | priority指定時のpreload要素 |

### 出力先

- DOMへのimg要素レンダリング
- Head要素へのpreload link（またはReactDOM.preload）

## 処理フロー

### 処理シーケンス

```
1. Image コンポーネントマウント
   ├─ RouterContext で App/Pages Router 判定
   └─ ImageConfigContext で画像設定取得
2. getImgProps で画像属性計算
   ├─ src の解決（静的インポート / URL）
   ├─ srcSet の生成（deviceSizes + imageSizes）
   ├─ sizes の計算
   └─ width / height / style の計算
3. ImageElement レンダリング
   ├─ fill: data-nimg="fill"
   ├─ 通常: data-nimg="1"
   ├─ placeholder 用スタイル適用
   └─ fetchPriority 設定
4. 画像読み込み処理
   ├─ img.decode() で非同期デコード
   ├─ onLoad コールバック実行
   └─ ブラーフェードアウト（setBlurComplete）
5. priority 指定時
   └─ ImagePreload コンポーネントでpreload実行
```

### フローチャート

```mermaid
flowchart TD
    A[Image コンポーネントマウント] --> B[ImageConfig 取得]
    B --> C[getImgProps]
    C --> D[ImageElement レンダリング]
    D --> E{priority?}
    E -->|Yes| F[ImagePreload]
    E -->|No| G[lazy loading]
    D --> H{画像読み込み完了}
    H -->|Yes| I[handleLoading]
    I --> J[img.decode]
    J --> K[onLoad コールバック]
    K --> L[setBlurComplete]
    H -->|Error| M[onError コールバック]
    M --> N[setShowAltText]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | srcSet自動生成 | deviceSizesとimageSizesからレスポンシブsrcSetを自動生成 | unoptimized=falseの場合 |
| BR-57-02 | fill時のparent position | fill使用時、親要素はabsolute/fixed/relativeのpositionが必要 | fill=trueの場合 |
| BR-57-03 | fill時のsizes推奨 | fill使用時にsizesが未指定または100vwで画像が小さい場合に警告 | 開発モード、fill=true |
| BR-57-04 | alt必須 | alt属性がnullの場合に開発モードで警告 | 開発モード |
| BR-57-05 | React 19対応 | fetchPriorityのプロパティ名をReactバージョンに応じて切り替え | use関数の存在で判定 |
| BR-57-06 | src属性の配置順 | srcをsizes/srcSetの後に配置してSafariの不要リクエストを防止 | 常時 |

### 計算ロジック

- allSizes: `[...deviceSizes, ...imageSizes].sort()`
- srcSet: allSizesの各サイズに対してloader関数でURLを生成
- ブラープレースホルダー: blurDataURLをbackground-imageとして設定し、読み込み完了後にフェードアウト

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 開発警告 | src未指定 | console.error |
| - | 開発警告 | alt未指定 | console.error |
| - | 開発警告 | fill時のparent positionが不正 | warnOnce |
| - | 開発警告 | width/heightの片方のみ変更 | warnOnce |
| - | 画像エラー | 画像読み込み失敗 | setShowAltText(true)でalt表示、onError呼び出し |

### リトライ仕様

画像読み込みのリトライは行わない。ブラウザのネイティブキャッシュメカニズムに委ねる。

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

該当なし

## パフォーマンス要件

- priority画像は`fetchPriority: high`で即時読み込み
- 通常画像は`loading: lazy`でビューポート外の遅延読み込み
- img.decode()による非同期デコードでメインスレッドブロッキングを回避
- loading属性をsrcの前に配置してSafari/Firefoxの遅延読み込み問題を回避

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

- localPatternsとremotePatternsによる許可URLの制限（サーバーサイド検証）
- ImageConfigのlocalPatternsはSSR時にconfigContextから取得（クライアントには公開されない）

## 備考

- `onLoadingComplete`はdeprecatedで将来削除予定
- `data-loaded-src`属性で重複読み込みイベントを防止
- App RouterではReactDOM.preloadでpreloadを実行、Pages Routerでは`<Head><link>`を使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | get-img-props.ts | `packages/next/src/shared/lib/get-img-props.ts` | ImageProps, ImgProps型定義 - src, width, height, fill, priority等 |
| 1-2 | image-config.ts | `packages/next/src/shared/lib/image-config.ts` | ImageConfigComplete型 - deviceSizes, imageSizes, formats, qualities |

**読解のコツ**: `getImgProps`は純粋関数として設計されており、ImageConfigとProps入力からimg属性（src, srcSet, sizes等）を計算する。コンポーネント本体とロジックが分離されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | image-component.tsx | `packages/next/src/client/image-component.tsx` | **358-434行目**: `Image`コンポーネント本体 - forwardRefで定義 |

**主要処理フロー**:
1. **360行目**: `useContext(RouterContext)` でRouter判定（App/Pages）
2. **365-385行目**: `useMemo`でImageConfig計算（allSizes, deviceSizes, qualities）
3. **402-407行目**: `getImgProps`で画像属性を計算
4. **409-434行目**: ImageElement + ImagePreload のレンダリング

#### Step 3: ImageElement（内部コンポーネント）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | image-component.tsx | `packages/next/src/client/image-component.tsx` | **183-308行目**: `ImageElement` - 実際のimg要素レンダリング |

**主要処理フロー**:
- **210-253行目**: ownRefコールバック - マウント時のバリデーションとcomplete画像の即時処理
- **258-305行目**: img要素のレンダリング（属性順序にSafari対応の配慮）
- **282-293行目**: onLoadハンドラ - handleLoading呼び出し
- **294-304行目**: onErrorハンドラ - alt表示とブラー解除

#### Step 4: 画像読み込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | image-component.tsx | `packages/next/src/client/image-component.tsx` | **62-167行目**: `handleLoading`関数 - decode, onLoad, 開発モード検証 |

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

```
Image (forwardRef コンポーネント)
    |
    +-- getImgProps(props, config) .......... 画像属性計算
    |       +-- defaultLoader() ............ URL 生成
    |
    +-- ImageElement (内部コンポーネント)
    |       +-- useMergedRef() ............. ref 合成
    |       +-- handleLoading() ............ 読み込み完了処理
    |       |       +-- img.decode() ....... 非同期デコード
    |       |       +-- onLoad callback
    |       |       +-- onLoadingComplete callback (deprecated)
    |       |       +-- setBlurComplete()
    |       +-- getDynamicProps() ........... fetchPriority 設定
    |
    +-- ImagePreload (条件付きコンポーネント)
            +-- ReactDOM.preload() [App Router]
            +-- <Head><link preload> [Pages Router]
```

### データフロー図

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

Props (src, width, ...) -----> getImgProps() ----------------> ImgProps (src, srcSet, sizes)
ImageConfig -----------------> |
                               v
ImgProps --------------------> ImageElement -----------------> <img> DOM 要素
                               |
                               +-> handleLoading() ----------> ブラーフェードアウト
                               |
priority: true --------------> ImagePreload -----------------> <link rel="preload">
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| image-component.tsx | `packages/next/src/client/image-component.tsx` | ソース | Imageコンポーネント本体（435行） |
| get-img-props.ts | `packages/next/src/shared/lib/get-img-props.ts` | ソース | 画像属性計算ロジック |
| image-config.ts | `packages/next/src/shared/lib/image-config.ts` | ソース | 画像設定型・デフォルト値 |
| image-config-context.shared-runtime.ts | `packages/next/src/shared/lib/image-config-context.shared-runtime.ts` | ソース | ImageConfigContext |
| image-loader.ts | `packages/next/src/shared/lib/image-loader.ts` | ソース | デフォルトイメージローダー |
| image-blur-svg.ts | `packages/next/src/shared/lib/image-blur-svg.ts` | ソース | ブラーSVG生成 |
| use-merged-ref.ts | `packages/next/src/client/use-merged-ref.ts` | ソース | ref合成ユーティリティ |
