---
title: "個人開発のパフォーマンス最適化入門【2026年最新】"
description: "Core Web Vitals（LCP・INP・CLS）の改善方法をNext.jsのコード例付きで徹底解説。Lighthouseスコア40点台から95点超まで改善した実践ノウハウを公開。"
url: "https://shiftb.dev/articles/indie-dev-performance-guide"
publishedAt: "2026-04-07"
updatedAt: "2026-04-07"
author: "立川修平（ぶべ）"
category: "indie-dev"
tags: ["パフォーマンス最適化", "Core Web Vitals", "Next.js", "個人開発", "SEO"]
---

# 個人開発のパフォーマンス最適化入門【2026年最新】

「Webサービスをリリースしたのに、なぜかユーザーがすぐ離脱する」——ShiftBの無料相談会で、リリース経験のある受講生の**約58%**がこの悩みを持っています。原因を調べると、その多くが**ページの表示速度**に問題を抱えていました。

Googleの調査によると、ページの読み込み時間が**1秒から3秒に増えると直帰率は32%上昇**し、**5秒になると90%上昇**します。さらに2026年現在、GoogleはCore Web Vitalsをランキング要因として重視しており、表示速度の改善は**SEOにも直結**します。

僕自身、ShiftBのサイトを**Lighthouseスコア40点台から95点以上**に改善した経験があります。その結果、ページの平均滞在時間は**1.5倍**に伸び、検索順位も複数のキーワードで**10位以上**上昇しました。

この記事では、ShiftB校長として**150名以上の受講生**の個人開発をサポートしてきた経験から、**Next.jsで作った個人開発サービスのパフォーマンスを劇的に改善する方法**を、Core Web Vitalsの基礎から具体的な実装コードまで徹底解説します。

## なぜパフォーマンスが個人開発の成功を左右するのか

個人開発サービスは、大企業のサービスと違ってブランド認知がありません。ユーザーが初めてアクセスしたとき、ページの表示が遅ければ**「このサービスは信頼できない」**と判断されて二度と戻ってきません。パフォーマンスは、個人開発者にとって最初のブランディングなのです。

### 表示速度がビジネス指標に与えるインパクト

表示速度の改善がどれだけビジネスに影響するか、具体的な数字で見てみましょう。

| 指標 | 改善前 | 改善後 | 変化率 |
| --- | --- | --- | --- |
| ページ読み込み時間 | 4.2秒 | 1.3秒 | -69% |
| 直帰率 | 68% | 41% | -27pt |
| 平均滞在時間 | 1分12秒 | 2分48秒 | +133% |
| コンバージョン率 | 1.2% | 2.8% | +133% |
| 検索順位（主要KW） | 23位 | 8位 | +15位 |

これはShiftBのサイトでの実際の改善データです。読み込み時間を約3秒短縮しただけで、直帰率は**27ポイント**改善し、コンバージョン率は**2倍以上**になりました。個人開発のサービスでここまで差がつくのです。

### SEOへの直接的な影響——Core Web Vitalsとランキング

2021年にGoogleが**Core Web Vitals**をランキング要因に組み込んで以来、表示速度はSEOにおいて無視できない要素になっています。2026年現在、GoogleはさらにINP（Interaction to Next Paint）を正式に指標に追加し、ページの「操作への応答性」も評価対象に含めています。

個人開発者にとって、広告費をかけずにユーザーを集められるSEOは最重要の集客チャネルです。パフォーマンス改善はSEO改善と直結しており、**1つの施策で「UX改善」と「検索順位向上」の両方**が得られるという、非常にコスパの高い投資なのです。

### パフォーマンスの「体感速度」とユーザー心理

人間の心理として、Webページの読み込みに対する感覚は以下のように分類されています。

| 応答時間 | ユーザーの感覚 | 個人開発への影響 |
| --- | --- | --- |
| 0〜100ms | 瞬時に感じる | 最高のUX。リピーターが増える |
| 100〜300ms | わずかに遅れを感じる | 許容範囲。問題なし |
| 300ms〜1秒 | 処理中だと認識する | ローディングUIが必要 |
| 1秒〜3秒 | 集中力が途切れ始める | 離脱が増え始める |
| 3秒以上 | 不満・苛立ちを感じる | 多くのユーザーが離脱する |

ポイントは、**「速い」ではなく「遅いと感じさせない」**ことです。実際の通信時間を短縮するのが理想ですが、ローディングアニメーションやスケルトンUIで体感速度を改善するのも有効な戦略です。

![Core Web Vitalsの3つの指標（LCP・INP・CLS）と個人開発への影響を示す図解](https://shiftb.dev/images/articles/indie-dev-performance-guide-cwv-overview.png)

## Core Web Vitals完全理解——3つの指標と測定方法

パフォーマンス改善の第一歩は、**何を改善すべきか**を正しく把握することです。GoogleのCore Web Vitalsは3つの指標で構成されています。それぞれの意味と目標値を理解しましょう。

### 3つの指標——LCP・INP・CLS

| 指標 | 正式名称 | 測定内容 | 良好 | 改善が必要 | 不良 |
| --- | --- | --- | --- | --- | --- |
| LCP | Largest Contentful Paint | 最大コンテンツの表示時間 | 2.5秒以下 | 2.5〜4秒 | 4秒超 |
| INP | Interaction to Next Paint | 操作への応答時間 | 200ms以下 | 200〜500ms | 500ms超 |
| CLS | Cumulative Layout Shift | レイアウトのズレ量 | 0.1以下 | 0.1〜0.25 | 0.25超 |

**LCP**はページのメインコンテンツ（ヒーロー画像やタイトルなど）がユーザーの画面に表示されるまでの時間です。**INP**はクリックやタップなどのユーザー操作に対して、画面が応答するまでの時間を測定します（2024年にFIDから置き換えられました）。**CLS**は読み込み中にテキストや画像がガタガタとズレる現象の度合いです。

### 測定ツール比較——何を使うべきか

パフォーマンスの測定ツールにはいくつかの種類があります。個人開発者が使うべきツールを目的別に整理しました。

| ツール | 種類 | コスト | リアルユーザー | おすすめ度 | 主な用途 |
| --- | --- | --- | --- | --- | --- |
| Lighthouse（DevTools） | ラボデータ | 無料 | ✕ | ★★★ | 開発中のチェック |
| PageSpeed Insights | ラボ＋フィールド | 無料 | ○ | ★★★ | 本番環境の総合診断 |
| Search Console | フィールドデータ | 無料 | ○ | ★★★ | サイト全体の傾向把握 |
| Web Vitals拡張機能 | リアルタイム | 無料 | ○（自分のみ） | ★★☆ | ブラウジング中の確認 |
| Vercel Speed Insights | フィールドデータ | 無料枠あり | ○ | ★★☆ | Next.js+Vercel環境 |

個人開発者の場合、まずは**Lighthouse**で開発中にチェックし、本番デプロイ後に**PageSpeed Insights**で確認するのが最もコスパの良い運用です。Vercelを使っているなら**Vercel Speed Insights**も導入しておくと、リアルユーザーのデータが自動で収集されるので便利です。

### Lighthouseの使い方——初心者でも3分で測定

Lighthouseの使い方はとてもシンプルです。以下の手順で測定できます。

1. **Chrome DevToolsを開く**（`F12` または `Cmd+Option+I`）——所要時間: 5秒
2. **「Lighthouse」タブを選択**——上部のタブから選ぶ
3. **カテゴリで「Performance」にチェック**——他のカテゴリはオフでOK
4. **デバイスで「Mobile」を選択**——Googleはモバイルファーストで評価する
5. **「Analyze page load」をクリック**——約30秒〜1分で結果が表示される

結果が表示されたら、まず**スコアと3つのCore Web Vitals指標**を確認しましょう。スコアが90以上なら「良好」、50〜89は「改善が必要」、49以下は「不良」です。個人開発サービスなら**まずは80点以上**を目指しましょう。

### 「ラボデータ」と「フィールドデータ」の違い

パフォーマンス測定で重要なのは、**ラボデータ**と**フィールドデータ**の違いを理解することです。ラボデータは固定の環境（ネットワーク速度・デバイス性能を統一）で計測されるのに対し、フィールドデータは実際のユーザーのブラウザから収集された値です。

Googleの検索ランキングに影響するのは**フィールドデータ**です。ただし、フィールドデータは十分なトラフィックがないと取得できません。リリース直後の個人開発サービスではラボデータで改善を進め、ユーザーが増えてきたらフィールドデータも確認するという運用がおすすめです。

## LCP改善——ページ表示速度を劇的に上げる実践テクニック

LCP（Largest Contentful Paint）は、ユーザーが「ページが表示された」と感じるまでの時間です。ShiftBの受講生のサイトを分析すると、**約70%がLCP 2.5秒超**で「改善が必要」に分類されていました。最もインパクトの大きい改善ポイントから順に解説します。

### 画像の最適化——最大のボトルネックを解消する

LCPの遅延原因の**約60%**が画像に起因しています。個人開発でよくあるのが、デザインツールからそのまま書き出した**2〜5MBのPNG画像**をそのまま使っているケースです。

**悪い例**——最適化されていない画像の実装:

```
<!-- ❌ 悪い例: 巨大なPNG画像をそのまま使用 -->
<img src="/hero-image.png" alt="ヒーローイメージ" />
<!-- 画像サイズ: 3.2MB, 表示に2.8秒 -->
```

**良い例**——Next.jsのImageコンポーネントで最適化:

```
// ✅ 良い例: next/imageで自動最適化
import Image from "next/image";

export function HeroSection() {
  return (
    <Image
      src="/hero-image.png"
      alt="ヒーローイメージ"
      width={1200}
      height={630}
      priority  // LCP要素にはpriorityを付与
      sizes="(max-width: 768px) 100vw, 1200px"
    />
  );
}
// 自動でWebP/AVIF変換 + リサイズ
// 画像サイズ: 約120KB, 表示に0.4秒
```

`next/image`を使うだけで、画像は自動的に**WebP/AVIF形式**に変換され、デバイスに応じた最適なサイズで配信されます。上の例では、**3.2MBが約120KBに圧縮**（96%削減）され、表示時間は**2.8秒から0.4秒**に短縮されました。

### フォントの最適化——CSSの読み込みをブロックしない

Webフォントの読み込みもLCPに大きく影響します。Google Fontsを使っている場合、外部CSSの読み込みが表示をブロックすることがあります。

```
// ✅ Next.jsでのフォント最適化（next/font）
import { Inter } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  display: "swap",       // テキストを先に表示
  preload: true,          // 事前読み込み
  variable: "--font-inter",
});

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja" className={inter.variable}>
      <body>{children}</body>
    </html>
  );
}
```

`next/font`を使うと、フォントファイルが**ビルド時にセルフホスティング**されるため、外部CDNへのリクエストが不要になります。`display: "swap"`を指定することで、フォント読み込み完了前でもシステムフォントでテキストが表示され、LCPが改善します。

### サーバーレスポンス時間（TTFB）の短縮

TTFB（Time to First Byte）は、サーバーがレスポンスを返すまでの時間です。LCPの起点となるため、TTFBが遅いとLCPも必然的に遅くなります。

個人開発サービスでTTFBを短縮するポイントは以下の3つです。

1. **SSG（静的生成）をできるだけ使う**——ビルド時にHTMLが生成されるため、サーバー処理がゼロ。LPや記事ページに最適
2. **ISR（増分静的再生成）で動的コンテンツに対応**——`revalidate`で再生成間隔を指定し、静的ファイルのメリットを活かす
3. **Vercelのエッジネットワークを活用**—— Next.js + Vercelの組み合わせでは、CDNが自動的にエッジキャッシュを行い、世界中どこからでも低レイテンシでアクセスできる

```
// ✅ ISRの実装例（App Router）
// app/products/[id]/page.tsx

export const revalidate = 3600; // 1時間ごとに再生成

export default async function ProductPage({
  params,
}: {
  params: { id: string };
}) {
  const product = await fetchProduct(params.id);
  return <ProductDetail product={product} />;
}

// SSG対象のパスを事前生成
export async function generateStaticParams() {
  const products = await fetchPopularProducts();
  return products.map((p) => ({ id: p.id }));
}
```

### レンダリングブロックリソースの排除

ブラウザがHTMLを解析するとき、CSSやJavaScriptがレンダリングをブロックすることがあります。特に個人開発でよくある問題は、**使っていないCSSの大量読み込み**です。

Next.jsを使っている場合、以下の対策が有効です。

- **Tailwind CSSの使用**——未使用のCSSを自動でパージするため、CSS全体のサイズが大幅に小さくなる（ShiftBのサイトでは**CSS全体がわずか12KB**）
- **外部スクリプトの遅延読み込み**—— Google Analyticsなどの外部スクリプトは`next/script`の`strategy="lazyOnload"`で読み込む
- **コンポーネントの動的インポート**——ファーストビューに不要なコンポーネントは`dynamic()`で遅延読み込み

```
// ✅ 外部スクリプトの遅延読み込み
import Script from "next/script";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        {children}
        {/* Google Analyticsは遅延読み込み */}
        <Script
          src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"
          strategy="lazyOnload"
        />
      </body>
    </html>
  );
}
```

## INP改善——ユーザー操作への応答性を高める

INP（Interaction to Next Paint）は2024年にFID（First Input Delay）に代わってCore Web Vitalsに採用された新しい指標です。ユーザーの**すべてのインタラクション**のうち、最も遅い応答時間をもとに評価されます。ShiftB受講生のサービスでは、**約45%**がINP 200ms超で「改善が必要」に該当していました。

### メインスレッドのブロッキングを防ぐ

INPの悪化の最大の原因は、**JavaScriptの重い処理がメインスレッドを占有**していることです。Reactアプリケーションでは、状態更新に伴う大量の再レンダリングが主なボトルネックになります。

```
// ❌ 悪い例: 検索のたびに全リストを再レンダリング
function ProductList({ products }: { products: Product[] }) {
  const [query, setQuery] = useState("");

  // 入力のたびに全商品をフィルタリング＋再レンダリング
  const filtered = products.filter((p) =>
    p.name.includes(query)
  );

  return (
    <>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      {filtered.map((p) => (
        <ProductCard key={p.id} product={p} />
      ))}
    </>
  );
}
```

```
// ✅ 良い例: useDeferredValueで非同期更新
import { useDeferredValue, useMemo } from "react";

function ProductList({ products }: { products: Product[] }) {
  const [query, setQuery] = useState("");
  const deferredQuery = useDeferredValue(query);

  // deferredQueryを使うことで、
  // 入力は即座に反映しつつリスト更新は遅延
  const filtered = useMemo(
    () =>
      products.filter((p) =>
        p.name.includes(deferredQuery)
      ),
    [products, deferredQuery]
  );

  return (
    <>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      {filtered.map((p) => (
        <ProductCard key={p.id} product={p} />
      ))}
    </>
  );
}
```

`useDeferredValue`を使うと、入力フィールドの更新は即座に画面に反映され、リストのフィルタリング（重い処理）はバックグラウンドで実行されます。これにより、ユーザーは入力のもたつきを感じなくなります。

### React.memoとuseMemoで不要な再レンダリングを防ぐ

Reactのコンポーネントは、親コンポーネントが再レンダリングされると子コンポーネントもすべて再レンダリングされます。表示内容が変わらないコンポーネントの再レンダリングはINPを悪化させる無駄な処理です。

```
// ✅ React.memoで不要な再レンダリングを防止
const ProductCard = memo(function ProductCard({
  product,
}: {
  product: Product;
}) {
  return (
    <div className="rounded-lg border p-4">
      <h3>{product.name}</h3>
      <p>{product.price}円</p>
    </div>
  );
});

// ✅ useMemoで計算結果をキャッシュ
function Dashboard({ orders }: { orders: Order[] }) {
  const totalRevenue = useMemo(
    () => orders.reduce((sum, o) => sum + o.amount, 0),
    [orders]
  );

  return <p>合計売上: {totalRevenue.toLocaleString()}円</p>;
}
```

ただし、**すべてのコンポーネントにmemoをつければいいわけではありません**。memo自体にもわずかなオーバーヘッドがあるため、再レンダリングが頻繁で描画コストの高いコンポーネント（リストアイテムなど）に限定して使いましょう。

### イベントハンドラの最適化

スクロールイベントやリサイズイベントなど、高頻度で発火するイベントの処理が重いとINPが大幅に悪化します。**デバウンス**や**スロットリング**を活用して、処理の実行回数を制限しましょう。

```
// ✅ スクロールイベントのスロットリング
import { useCallback, useEffect, useRef } from "react";

function useThrottledScroll(
  callback: () => void,
  delay: number
) {
  const lastRun = useRef(Date.now());

  useEffect(() => {
    const handleScroll = () => {
      if (Date.now() - lastRun.current >= delay) {
        callback();
        lastRun.current = Date.now();
      }
    };

    window.addEventListener("scroll", handleScroll, {
      passive: true, // パッシブリスナーでスクロール性能を向上
    });
    return () =>
      window.removeEventListener("scroll", handleScroll);
  }, [callback, delay]);
}
```

`passive: true`オプションをつけることで、ブラウザはスクロール処理をイベントハンドラの完了を待たずに実行できるようになり、スクロールのカクつきが解消されます。

### Server Componentsの活用でクライアントJSを削減

Next.js App Routerでは、コンポーネントはデフォルトで**Server Component**です。Server Componentはサーバー側でHTMLにレンダリングされるため、クライアントに送られるJavaScriptバンドルに含まれません。

クライアントに送るJSを減らすことで、メインスレッドの負荷が下がりINPが改善します。「`use client`」はインタラクティブ性が必要なコンポーネントにだけ付与しましょう。

![パフォーマンス最適化の優先順位フローチャート — LCP→INP→CLSの順に改善する手順](https://shiftb.dev/images/articles/indie-dev-performance-guide-optimization-flow.png)

## CLS改善——レイアウトのズレをゼロにする

CLS（Cumulative Layout Shift）は、ページ読み込み中のレイアウトのズレを測定する指標です。記事を読んでいる最中にテキストがガクンとずれたり、クリックしようとしたボタンが移動したりする体験は、ユーザーにとって大きなストレスです。ShiftB受講生のサービスでは、**約35%**がCLS 0.1超で改善が必要な状態でした。

### 画像・動画にサイズ属性を指定する

CLSの最大の原因は、**画像や動画の表示サイズが事前に確保されていない**ことです。Next.jsの`Image`コンポーネントを使えば自動的に解決されますが、通常の`<img>`タグを使う場合は必ず`width`と`height`を指定しましょう。

```
<!-- ❌ 悪い例: サイズ未指定 → 画像読み込み時にレイアウトがズレる -->
<img src="/screenshot.png" alt="スクリーンショット" />

<!-- ✅ 良い例: サイズ指定でレイアウトシフトを防止 -->
<img
  src="/screenshot.png"
  alt="スクリーンショット"
  width="800"
  height="450"
  style="aspect-ratio: 800/450; width: 100%; height: auto;"
/>
```

### Webフォントによるレイアウトシフトを防ぐ

Webフォントの読み込みで、テキストのサイズが変わりレイアウトがズレる現象を**FOUT（Flash of Unstyled Text）**といいます。先ほどLCPの章で紹介した`next/font`を使えば、フォントの`size-adjust`が自動計算されてレイアウトシフトが最小限に抑えられます。

### 動的コンテンツの表示スペースを事前確保する

広告バナーや通知バー、遅延読み込みされるコンテンツなど、あとから挿入される要素がレイアウトシフトの原因になることがあります。

```
// ✅ スケルトンUIで表示スペースを事前確保
function ProductCardSkeleton() {
  return (
    <div className="animate-pulse rounded-lg border p-4">
      <div className="mb-4 h-48 rounded bg-gray-200" />
      <div className="mb-2 h-4 w-3/4 rounded bg-gray-200" />
      <div className="h-4 w-1/2 rounded bg-gray-200" />
    </div>
  );
}

// Suspenseと組み合わせて使う
import { Suspense } from "react";

export default function ProductsPage() {
  return (
    <Suspense
      fallback={
        <div className="grid grid-cols-3 gap-6">
          {Array.from({ length: 6 }).map((_, i) => (
            <ProductCardSkeleton key={i} />
          ))}
        </div>
      }
    >
      <ProductList />
    </Suspense>
  );
}
```

スケルトンUIを使うことで、データ読み込み中でもレイアウトが安定し、CLS値が**0**に近づきます。さらに、ユーザーにとっても「読み込み中」であることが視覚的にわかるため、体感の待ち時間が短く感じられます。

### CSS containで不要な再レイアウトを防ぐ

CSSの`contain`プロパティを使うと、ブラウザにレイアウト計算の範囲を限定させることができます。

```
/* ✅ レイアウト影響を局所化 */
.card-container {
  contain: layout style;
}

/* サイドバーの変更がメインコンテンツに影響しない */
.sidebar {
  contain: layout;
}
```

## Next.js特有のパフォーマンス最適化テクニック

ここまでCore Web Vitalsの3指標ごとの改善方法を解説してきました。ここからは、Next.jsを使った個人開発で特に効果の大きい最適化テクニックを紹介します。

### レンダリング戦略の使い分け——SSG / ISR / SSR / CSR

Next.jsの強みは、ページごとに最適なレンダリング戦略を選べることです。個人開発サービスでの使い分けの目安を整理しました。

| レンダリング戦略 | ビルド時生成 | リクエスト時処理 | パフォーマンス | 適したページ |
| --- | --- | --- | --- | --- |
| SSG（静的生成） | ○ | なし | ★★★ | LP・ブログ・ヘルプ |
| ISR（増分静的再生成） | ○ | 定期再生成 | ★★★ | 商品一覧・記事詳細 |
| SSR（サーバーサイドレンダリング） | ✕ | 毎回生成 | ★★☆ | ダッシュボード・検索結果 |
| CSR（クライアントサイドレンダリング） | ✕ | クライアント | ★☆☆ | ログイン後の管理画面 |

個人開発サービスでは、**トップページ・LP・記事ページはSSGまたはISR**で、**ログイン後のダッシュボードはSSRまたはCSR**で構成するのが鉄板パターンです。検索エンジンがクロールする公開ページは静的に生成しておくことで、TTFBが極限まで短くなりLCPが大幅に改善します。

### バンドルサイズの最適化——不要なJavaScriptを削ぎ落とす

クライアントに配信されるJavaScriptの量は、パフォーマンスに直結します。まずは現状のバンドルサイズを確認しましょう。

```
# バンドルサイズの分析
npx next build
# ビルド結果にページごとのサイズが表示される

# より詳細な分析をするなら
npm install -D @next/bundle-analyzer

// next.config.ts
import bundleAnalyzer from "@next/bundle-analyzer";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true",
});

export default withBundleAnalyzer(nextConfig);

// 実行
ANALYZE=true npx next build
```

バンドルサイズが大きい原因として多いのは以下の3つです。

1. **重い日付ライブラリ**——`moment.js`（約300KB）の代わりに`date-fns`（tree-shakableで必要な関数のみ取り込める）を使う
2. **アイコンライブラリの全体インポート**——`import { FaHome } from "react-icons/fa"`のように個別インポートする（全体インポートだと数百KB増える）
3. **不要なポリフィル**——ターゲットブラウザを適切に設定し、モダンブラウザ向けにビルドする

### プリフェッチとルーティングの最適化

Next.jsのApp Routerでは、`Link`コンポーネントがビューポートに入った時点で遷移先のページデータを自動でプリフェッチします。これによりページ遷移が瞬時に行われ、SPA（Single Page Application）のようなスムーズなナビゲーションが実現します。

```
// ✅ Linkのプリフェッチ（デフォルトで有効）
import Link from "next/link";

export function Navigation() {
  return (
    <nav>
      <Link href="/products">商品一覧</Link>
      <Link href="/about">概要</Link>
      {/* 頻繁にアクセスしないページはプリフェッチを無効化 */}
      <Link href="/terms" prefetch={false}>
        利用規約
      </Link>
    </nav>
  );
}
```

ただし、プリフェッチはネットワーク通信を伴うため、すべてのリンクでプリフェッチが有効だとモバイルユーザーのデータ通信量が増えます。利用規約やプライバシーポリシーなど、アクセス頻度の低いページは`prefetch={false}`で無効化しましょう。

### Streaming SSRとSuspenseで体感速度を上げる

Next.js App Routerでは、**Streaming SSR**が標準でサポートされています。ページ全体の生成を待たずに、準備できた部分から順次ブラウザに送信する仕組みです。

```
// ✅ Streaming SSRの実装例
import { Suspense } from "react";

export default function DashboardPage() {
  return (
    <div className="grid grid-cols-12 gap-6">
      {/* ヘッダーは即座に表示 */}
      <header className="col-span-12">
        <h1>ダッシュボード</h1>
      </header>

      {/* 統計情報は読み込み中でもスケルトンを表示 */}
      <Suspense fallback={<StatsSkeleton />}>
        <StatsPanel />
      </Suspense>

      {/* グラフは独立して読み込み */}
      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart />
      </Suspense>

      {/* 最新の注文一覧も独立して読み込み */}
      <Suspense fallback={<TableSkeleton />}>
        <RecentOrders />
      </Suspense>
    </div>
  );
}
```

各セクションを`Suspense`で囲むことで、データベースからの取得が遅いコンポーネントがあっても他の部分は先に表示されます。LCPの改善に大きく貢献する手法です。

### 画像配信の最適化——next/imageの詳細設定

`next/image`にはさまざまな最適化オプションがあります。個人開発サービスで特に効果的な設定を紹介します。

```
// next.config.ts での画像最適化設定
const nextConfig = {
  images: {
    // 対応フォーマット（AVIFは圧縮率が高いが変換に時間がかかる）
    formats: ["image/avif", "image/webp"],
    // デバイスごとの画像サイズ
    deviceSizes: [640, 750, 828, 1080, 1200],
    // レスポンシブ用のサイズ
    imageSizes: [16, 32, 48, 64, 96, 128, 256],
    // 外部画像のドメインを許可
    remotePatterns: [
      {
        protocol: "https",
        hostname: "**.supabase.co",
      },
    ],
  },
};
```

![Next.jsのレンダリング戦略比較図 — SSG・ISR・SSR・CSRの使い分けと各ページタイプへの適用](https://shiftb.dev/images/articles/indie-dev-performance-guide-nextjs-rendering.png)

## Claude Codeを使ったパフォーマンス改善ワークフロー

パフォーマンス改善は地道な作業の連続ですが、**AI駆動開発ツールを活用することで効率を大幅に上げられます**。ここではClaude Codeを使ったパフォーマンス改善の実践ワークフローを紹介します。

### Step 1: 現状分析——Lighthouseレポートの読み解き

まず、Lighthouseのレポートを取得し、Claude Codeに分析を依頼します。

```
# Claude Codeに依頼するプロンプト例
"Lighthouseのパフォーマンススコアが62点です。
以下の診断結果をもとに、改善の優先順位をつけてください:
- LCP: 3.8秒（目標: 2.5秒以下）
- INP: 280ms（目標: 200ms以下）
- CLS: 0.15（目標: 0.1以下）
- 未使用のJavaScript: 420KB
- 画像の最適化提案: 8枚"

# Claude Codeが優先順位を分析し、
# 具体的な改善コードを提案してくれる
```

Claude Codeは、レポートの数字をもとに**最もインパクトの大きい改善**から順番に具体的なコード修正を提案してくれます。ShiftBの受講生の場合、このアプローチで平均**2〜3時間**でLighthouseスコアを**20〜30ポイント**改善できています。

### Step 2: 自動修正——コードベース全体の最適化

Claude Codeは、プロジェクト全体のコードを理解したうえで最適化を行えます。

```
# コードベース全体の画像を最適化
"プロジェクト内のすべての<img>タグを確認し、
next/imageに置き換えてください。
priorityはファーストビューの画像のみに
付与してください。"

# バンドルサイズの改善
"package.jsonのdependenciesを確認し、
バンドルサイズの大きいライブラリを
軽量な代替に置き換える提案をしてください。"

# 不要な'use client'の削除
"プロジェクト内の'use client'ディレクティブを
確認し、Server Componentで問題ないものは
ディレクティブを削除してください。"
```

### Step 3: 継続的な監視——パフォーマンスバジェットの設定

せっかく改善しても、新しい機能の追加でパフォーマンスが劣化しては意味がありません。**パフォーマンスバジェット**を設定し、閾値を超えたらアラートが出る仕組みを作りましょう。

```
// パフォーマンスバジェットの設定例
// lighthouse.config.js
export default {
  ci: {
    assert: {
      assertions: {
        "categories:performance": ["error", { minScore: 0.8 }],
        "largest-contentful-paint": [
          "error",
          { maxNumericValue: 2500 },
        ],
        "interactive": [
          "warn",
          { maxNumericValue: 3000 },
        ],
        "cumulative-layout-shift": [
          "error",
          { maxNumericValue: 0.1 },
        ],
      },
    },
  },
};
```

このバジェットをCI/CDパイプライン（GitHub Actionsなど）に組み込めば、プルリクエストごとにパフォーマンスが自動チェックされ、劣化した場合にマージをブロックできます。

### パフォーマンス改善チェックリスト

最後に、個人開発サービスのパフォーマンス改善で確認すべき項目をチェックリストにまとめました。上から順に対応していくと、最もインパクトの大きい改善から取り組めます。

| 優先度 | 改善項目 | 対象指標 | 期待される効果 | 所要時間目安 |
| --- | --- | --- | --- | --- |
| ★★★ | 画像をnext/imageに置き換え | LCP | LCP 1〜3秒短縮 | 30分〜1時間 |
| ★★★ | next/fontでフォント最適化 | LCP, CLS | LCP 0.3〜0.5秒短縮 | 15分 |
| ★★★ | SSG/ISRの適用 | LCP | TTFB 50〜200ms短縮 | 1〜2時間 |
| ★★☆ | 外部スクリプトの遅延読み込み | LCP, INP | LCP 0.5〜1秒短縮 | 15分 |
| ★★☆ | 不要なuse clientの削除 | INP | JS削減 10〜50KB | 30分〜1時間 |
| ★★☆ | 画像・動画のサイズ属性指定 | CLS | CLS 0に近づく | 15〜30分 |
| ★☆☆ | 重いライブラリの置き換え | INP | JS削減 50〜300KB | 1〜3時間 |
| ★☆☆ | Suspenseでストリーミング | LCP | 体感速度の向上 | 1〜2時間 |

## よくある質問（FAQ）

### Q1. Lighthouseのスコアは何点を目指すべきですか？

個人開発サービスなら、まずは**80点以上**を目標にしましょう。90点以上になるとGoogleの評価も「良好」に入り、SEO面での恩恵が大きくなります。ただし、100点を目指して過度な最適化に時間をかけるよりも、80点を超えたら機能開発やマーケティングに時間を使う方が、サービス全体の成長にはプラスです。

### Q2. パフォーマンス改善にどれくらい時間をかけるべきですか？

初回の改善は**1〜2日**あれば十分です。上で紹介したチェックリストの★★★項目だけで大幅に改善できます。ShiftBの受講生の実績では、`next/image`への置き換えと`next/font`の導入だけで、平均**25ポイント**のスコア改善が見られました。その後は、新機能追加時に劣化していないかを確認する程度で十分です。

### Q3. VercelのSpeed Insightsは導入すべきですか？

**おすすめです**。Vercel Speed Insightsはフリープランでも使え、実際のユーザーのCore Web Vitalsデータが自動で収集されます。Lighthouseはラボデータなので、リアルユーザーの体験を知るためにはフィールドデータが必要です。特にモバイルユーザーの体験を把握するのに役立ちます。導入は`@vercel/speed-insights`パッケージを追加するだけで、**5分もかかりません**。

### Q4. 画像はWebPとAVIFどちらを使うべきですか？

Next.jsの`next/image`を使っているなら、**両方対応**するのが理想です。`next.config.ts`で`formats: ["image/avif", "image/webp"]`と設定すると、ブラウザの対応状況に応じて最適なフォーマットが配信されます。AVIFはWebPよりさらに**20〜50%**圧縮率が高いですが、エンコード時間が長いため、ビルド時間が気になる場合はWebPのみでも十分です。

### Q5. Server ComponentsとClient Componentsの使い分けの目安は？

基本ルールは「**インタラクティブ性が必要かどうか**」です。`useState`、`useEffect`、イベントハンドラ（`onClick`等）を使うコンポーネントだけを`"use client"`にし、それ以外はServer Componentのままにしましょう。ShiftBのサイトでは、全コンポーネントの**約75%**がServer Componentで、クライアントに送るJavaScriptを最小限に抑えています。

### Q6. パフォーマンス改善で最もコスパが良い施策は何ですか？

断然**画像の最適化**です。`next/image`への置き換えは作業時間が短い割に効果が大きく、LCPが**1〜3秒**改善するケースがほとんどです。特にヒーロー画像やサムネイル画像の最適化は、**15分の作業でLighthouseスコアが10〜20ポイント上がる**こともあります。次にコスパが良いのは、外部スクリプト（Google Analyticsなど）の遅延読み込みです。

### Q7. モバイルのスコアがデスクトップより大幅に低いのですが…

これは正常です。Lighthouseのモバイルテストは、**中速の4G回線**と**CPU性能が制限された端末**をシミュレーションしています。デスクトップよりスコアが**20〜30ポイント**低くなるのは一般的です。Googleはモバイルファーストインデックスを採用しているため、**モバイルのスコアを優先的に改善**しましょう。特に効果が大きいのは、画像のサイズ削減と不要なJavaScriptの削除です。
