# 機能設計書 59-next/font

## 概要

本ドキュメントは、Next.jsの`next/font`機能の機能設計を記述する。`next/font`はGoogle Fontsおよびローカルフォントファイルのビルドタイムでのダウンロード・セルフホスティング・CSS生成を自動化するフォント最適化機能であり、CLS（Cumulative Layout Shift）の排除とフォントのパフォーマンス最適化を実現する。

### 本機能の処理概要

**業務上の目的・背景**：Webフォントの外部CDNからの読み込みは、パフォーマンスの低下（ネットワーク遅延、レイアウトシフト）とプライバシーの懸念（第三者サーバーへのリクエスト）を引き起こす。`next/font`はビルド時にフォントファイルをダウンロードしてセルフホスティングすることで、これらの問題を解決する。さらにフォールバックフォントのメトリクスを自動計算し、`size-adjust`等のCSSプロパティでレイアウトシフトを最小化する。

**機能の利用シーン**：Google Fontsの使用（`next/font/google`）、ローカルフォントファイルの最適化（`next/font/local`）、CSS Variables経由でのフォント適用、Tailwind CSSとの統合。

**主要な処理内容**：
1. Google Fontsローダー: CSS取得 → フォントファイルダウンロード → セルフホスティングURL生成 → @font-face CSS生成
2. ローカルフォントローダー: フォントファイル読み込み → 出力ディレクトリへの書き出し → @font-face CSS生成
3. フォールバックフォントメトリクス計算（ascent-override, descent-override, line-gap-override, size-adjust）
4. CSS Moduleの自動生成（className, style, variable）
5. フォント関数呼び出しのバリデーション

**関連システム・外部連携**：Google Fonts API（fonts.googleapis.com）、Webpack/Turbopackローダー、fontkitライブラリ（フォントメタデータ解析）。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ドキュメント (_document) | 補助機能 | Next Font Manifestに基づくフォントのpreload・preconnectリンク生成 |

## 機能種別

ビルドタイム最適化 / フォント管理 / CSS生成

## 入力仕様

### 入力パラメータ（Google Fonts）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fontFamily | string | Yes | Google Fontsファミリ名（関数名から推定） | Google Fontsメタデータに存在すること |
| weight | string \| string[] | Conditional | フォントウェイト（例: '400', '700'） | 可変フォントでは省略可 |
| style | string \| string[] | No | フォントスタイル（'normal', 'italic'） | 有効なスタイル値 |
| subsets | string[] | No | プリロードするサブセット（例: ['latin']） | フォントに存在するサブセット |
| display | Display | No | font-display値（デフォルト: 'swap'） | 'auto','block','swap','fallback','optional' |
| preload | boolean | No | プリロード有効化（デフォルト: true） | boolean |
| variable | CssVariable | No | CSS変数名（例: '--font-inter'） | `--`で始まる文字列 |
| fallback | string[] | No | フォールバックフォントリスト | - |
| adjustFontFallback | boolean | No | フォールバックメトリクス調整（デフォルト: true） | boolean |
| axes | string[] | No | 可変フォントの追加軸 | フォントに存在する軸 |

### 入力パラメータ（ローカルフォント）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| src | string \| FontFile[] | Yes | フォントファイルパスまたは配列 | ファイルが存在すること |
| display | Display | No | font-display値 | - |
| weight | string | No | デフォルトフォントウェイト | - |
| style | string | No | デフォルトフォントスタイル | - |
| fallback | string[] | No | フォールバックフォントリスト | - |
| preload | boolean | No | プリロード有効化 | boolean |
| variable | CssVariable | No | CSS変数名 | - |
| adjustFontFallback | string \| false | No | フォールバックフォント種別（'Arial'/'Times New Roman'/false） | - |
| declarations | Declaration[] | No | カスタム@font-faceプロパティ | - |

### 入力データソース

- フォント関数呼び出しの引数（ビルド時に解析）
- Google Fonts API（fonts.googleapis.com）
- ローカルフォントファイル（プロジェクト内）
- Google Fontsメタデータ（組み込み）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| css | string | @font-face宣言を含むCSS文字列 |
| fallbackFonts | string[] | フォールバックフォントリスト |
| weight | string \| undefined | 単一ウェイト時のウェイト値 |
| style | string \| undefined | 単一スタイル時のスタイル値 |
| variable | CssVariable \| undefined | CSS変数名 |
| adjustFontFallback | AdjustFontFallback \| undefined | フォールバックメトリクス |

### 出力先

- .next/static/media/ にフォントファイルを書き出し
- CSS Moduleとしてスタイル適用（className, style.fontFamily）
- CSS変数（variable属性指定時）

## 処理フロー

### 処理シーケンス（Google Fonts）

```
1. フォント関数呼び出しのバリデーション (validateGoogleFontFunctionCall)
   └─ fontFamily, weights, styles, subsets等の検証
2. フォント軸の取得 (getFontAxes)
   └─ weights, styles, selectedVariableAxes から軸パラメータ生成
3. Google Fonts URL生成 (getGoogleFontsUrl)
   └─ fontFamily + fontAxes + display でURL構築
4. CSSフェッチ (fetchCSSFromGoogleFonts)
   ├─ キャッシュチェック (cssCache)
   └─ Google Fonts APIからCSS取得
5. フォントファイルURL抽出 (findFontFilesInCss)
   └─ @font-faceのsrc URLを抽出、プリロード判定
6. フォントファイルダウンロード (fetchFontFile)
   ├─ キャッシュチェック (fontCache)
   └─ フォントバイナリダウンロード
7. セルフホスティングURL生成 (emitFontFile)
   └─ .next/static/media/ にファイル書き出し
8. CSS書き換え
   └─ Google Fonts URLをセルフホスティングURLに置換
9. フォールバックメトリクス取得 (getFallbackFontOverrideMetrics)
   └─ 事前計算されたメトリクス値を返却
```

### フローチャート

```mermaid
flowchart TD
    A[フォント関数呼び出し] --> B{Google or Local?}
    B -->|Google| C[validateGoogleFontFunctionCall]
    B -->|Local| D[validateLocalFontFunctionCall]
    C --> E[getFontAxes]
    E --> F[getGoogleFontsUrl]
    F --> G[fetchCSSFromGoogleFonts]
    G --> H[findFontFilesInCss]
    H --> I[fetchFontFile x N]
    I --> J[emitFontFile x N]
    J --> K[CSS URL 置換]
    K --> L[adjustFontFallback メトリクス]
    L --> M[結果返却]
    D --> N[フォントファイル読み込み]
    N --> O[emitFontFile]
    O --> P[@font-face CSS 生成]
    P --> Q[fontkit メトリクス解析]
    Q --> R[adjustFontFallback 計算]
    R --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | ビルドタイム実行 | フォントの取得・最適化はビルド時に実行される | 常時 |
| BR-59-02 | CSSキャッシュ | CSSフェッチ結果はcssCache Mapでキャッシュ | Google Fonts |
| BR-59-03 | フォントキャッシュ | フォントファイルはfontCache Mapでキャッシュ | Google Fonts |
| BR-59-04 | クライアント/サーバー重複防止 | CSSキャッシュは1回目にset、2回目にdeleteして重複フェッチを防止 | 常時 |
| BR-59-05 | 開発モードフォールバック | 開発モードでフォントダウンロード失敗時はフォールバックCSSを生成 | isDev === true |
| BR-59-06 | カスタムfont-family | declarations内でfont-familyが指定された場合、variableNameの使用をスキップ | ローカルフォント |

### 計算ロジック

- フォールバックメトリクス（Google Fonts）: 事前計算されたascent-override, descent-override, line-gap-override, size-adjustの値テーブルから取得
- フォールバックメトリクス（ローカル）: fontkitでフォントメタデータを解析し、getFallbackMetricsFromFontFileで計算
- CSS URL置換: Google Fonts URLをescapeStringRegexpでエスケープし、正規表現置換

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

該当なし（ファイルシステム操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | nextFontError | Google Fontsからのフェッチ失敗 | 開発モード: フォールバックCSS生成、本番: エラースロー |
| - | nextFontError | フォントファイルのダウンロード失敗 | 同上 |
| - | バリデーションエラー | 無効なフォント名、ウェイト、スタイル | nextFontErrorスロー |
| - | console.error | fontkitでのメタデータ解析失敗 | エラーログ出力、フォールバックメトリクスなしで続行 |

### リトライ仕様

Google Fontsからのフェッチにはretryモジュールが使用される（packages/font/src/google/retry.ts）。

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

該当なし

## パフォーマンス要件

- ビルドタイム実行のため、ランタイムパフォーマンスへの影響なし
- フォントファイルのセルフホスティングにより、外部CDNへのリクエストを排除
- preload属性によるフォントの事前読み込みでFOUT/FOITを最小化

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

- Google Fonts API通信はHTTPS
- フォントファイルはセルフホスティングされるため、第三者CDNへのユーザーデータ送信なし
- プロキシエージェント対応（get-proxy-agent.ts）

## 備考

- `next/font/google`と`next/font/local`の2つのサブモジュールを提供
- NextFont型: `{ className: string, style: { fontFamily, fontWeight?, fontStyle? } }`
- NextFontWithVariable型: NextFont + `{ variable: string }`
- CSS変数はTailwind CSSとの統合に便利

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/font/src/types.ts` | **1-12行目**: CssVariable, Display, NextFont, NextFontWithVariable型 |
| 1-2 | constants.ts | `packages/font/src/constants.ts` | 定数定義 |

**読解のコツ**: `next/font`はpackages/font/に独立パッケージとして配置されている。google/とlocal/サブディレクトリにそれぞれのローダーが実装されている。

#### Step 2: Google Fontsローダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | loader.ts (google) | `packages/font/src/google/loader.ts` | **28-196行目**: `nextFontGoogleFontLoader` - メインローダー関数 |

**主要処理フロー**:
1. **35-46行目**: `validateGoogleFontFunctionCall` で入力検証
2. **49-54行目**: `getFontAxes` でフォント軸パラメータ生成
3. **57行目**: `getGoogleFontsUrl` でAPI URL構築
4. **80-92行目**: CSSフェッチ（キャッシュ管理つき）
5. **101-104行目**: `findFontFilesInCss` でフォントファイルURL抽出
6. **107-140行目**: フォントファイルダウンロード + emitFontFile
7. **151-157行目**: CSS内URLの置換（Google → セルフホスティング）

#### Step 3: ローカルフォントローダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | loader.ts (local) | `packages/font/src/local/loader.ts` | **15-114行目**: `nextFontLocalFontLoader` - メインローダー関数 |

**主要処理フロー**:
1. **23-33行目**: `validateLocalFontFunctionCall` で入力検証
2. **37-90行目**: フォントファイル読み込み → emitFontFile → @font-face CSS生成
3. **93-102行目**: フォールバックメトリクス計算（fontkitベース）

#### Step 4: バリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | validate-google-font-function-call.ts | `packages/font/src/google/validate-google-font-function-call.ts` | Google Fonts用バリデーション |
| 4-2 | validate-local-font-function-call.ts | `packages/font/src/local/validate-local-font-function-call.ts` | ローカルフォント用バリデーション |

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

```
next/font/google (loader)
    |
    +-- validateGoogleFontFunctionCall()
    +-- getFontAxes()
    +-- getGoogleFontsUrl()
    +-- fetchCSSFromGoogleFonts()
    |       +-- fetch() via fetchResource()
    |       +-- retry()
    +-- findFontFilesInCss()
    +-- fetchFontFile()
    |       +-- fetch() via fetchResource()
    +-- emitFontFile()
    +-- getFallbackFontOverrideMetrics()

next/font/local (loader)
    |
    +-- validateLocalFontFunctionCall()
    +-- resolve() + readFile()
    +-- emitFontFile()
    +-- fontFromBuffer() (fontkit)
    +-- pickFontFileForFallbackGeneration()
    +-- getFallbackMetricsFromFontFile()
```

### データフロー図

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

フォント関数引数 -----------> validate*() -----------------> 検証済みパラメータ
                              |
Google Fonts API -----------> fetchCSS/fetchFont -----------> CSSテキスト + フォントバイナリ
                              |
                              +-> emitFontFile() -----------> .next/static/media/font.woff2
                              +-> CSS URL 置換 -------------> @font-face CSS
                              +-> フォールバック計算 --------> adjustFontFallback CSS
                              |
ローカルフォントファイル ----> readFile() -------------------> フォントバイナリ
                              |
                              +-> fontkit 解析 -------------> フォントメタデータ
                              +-> @font-face CSS 生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| loader.ts (google) | `packages/font/src/google/loader.ts` | ソース | Google Fontsローダー（196行） |
| loader.ts (local) | `packages/font/src/local/loader.ts` | ソース | ローカルフォントローダー（114行） |
| types.ts | `packages/font/src/types.ts` | ソース | 型定義（12行） |
| validate-google-font-function-call.ts | `packages/font/src/google/validate-google-font-function-call.ts` | ソース | Google Fontsバリデーション |
| validate-local-font-function-call.ts | `packages/font/src/local/validate-local-font-function-call.ts` | ソース | ローカルフォントバリデーション |
| get-font-axes.ts | `packages/font/src/google/get-font-axes.ts` | ソース | フォント軸パラメータ生成 |
| get-google-fonts-url.ts | `packages/font/src/google/get-google-fonts-url.ts` | ソース | Google Fonts URL生成 |
| fetch-css-from-google-fonts.ts | `packages/font/src/google/fetch-css-from-google-fonts.ts` | ソース | Google Fonts CSS取得 |
| fetch-font-file.ts | `packages/font/src/google/fetch-font-file.ts` | ソース | フォントファイルダウンロード |
| find-font-files-in-css.ts | `packages/font/src/google/find-font-files-in-css.ts` | ソース | CSS内フォントファイルURL抽出 |
| get-fallback-font-override-metrics.ts | `packages/font/src/google/get-fallback-font-override-metrics.ts` | ソース | Google Fontsフォールバックメトリクス |
| get-fallback-metrics-from-font-file.ts | `packages/font/src/local/get-fallback-metrics-from-font-file.ts` | ソース | ローカルフォントフォールバックメトリクス |
| pick-font-file-for-fallback-generation.ts | `packages/font/src/local/pick-font-file-for-fallback-generation.ts` | ソース | フォールバック生成用ファイル選択 |
| retry.ts | `packages/font/src/google/retry.ts` | ソース | リトライロジック |
| fetch-resource.ts | `packages/font/src/google/fetch-resource.ts` | ソース | リソースフェッチ |
| get-proxy-agent.ts | `packages/font/src/google/get-proxy-agent.ts` | ソース | プロキシエージェント |
| next-font-error.ts | `packages/font/src/next-font-error.ts` | ソース | エラー生成 |
