個人開発··25min read

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

パフォーマンス最適化Core Web VitalsNext.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の基礎から具体的な実装コードまで徹底解説します。

この記事を書いた人:立川修平(ぶべ)

  • ShiftB校長。受講生150名以上の個人開発サイトのパフォーマンス改善をサポート
  • ShiftBのサイトをLighthouseスコア40点台から95点超に改善。Next.js×Vercelでの最適化に精通
  • SNSフォロワー計3万人超。AI駆動開発・個人開発のノウハウを毎日発信

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

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

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

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

指標改善前改善後変化率
ページ読み込み時間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)と個人開発への影響を示す図解

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

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

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

指標正式名称測定内容良好改善が必要不良
LCPLargest Contentful Paint最大コンテンツの表示時間2.5秒以下2.5〜4秒4秒超
INPInteraction to Next Paint操作への応答時間200ms以下200〜500ms500ms超
CLSCumulative Layout Shiftレイアウトのズレ量0.1以下0.1〜0.250.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の検索ランキングに影響するのはフィールドデータです。 ただし、フィールドデータは十分なトラフィックがないと取得できません。 リリース直後の個人開発サービスではラボデータで改善を進め、 ユーザーが増えてきたらフィールドデータも確認するという運用がおすすめです。

AI時代のアプリ開発コース

ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながらAI駆動開発を身につけるコースです。ただ作って終わりではなく、コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担えるところまで現役エンジニアがサポートします。

AIシフトコースを見る →

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/scriptstrategy="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の順に改善する手順

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

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

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

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

<!-- ❌ 悪い例: サイズ未指定 → 画像読み込み時にレイアウトがズレる -->
<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;
}

AI時代のアプリ開発コース

ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながらAI駆動開発を身につけるコースです。ただ作って終わりではなく、コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担えるところまで現役エンジニアがサポートします。

AIシフトコースを見る →

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の使い分けと各ページタイプへの適用

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に置き換えLCPLCP 1〜3秒短縮30分〜1時間
★★★next/fontでフォント最適化LCP, CLSLCP 0.3〜0.5秒短縮15分
★★★SSG/ISRの適用LCPTTFB 50〜200ms短縮1〜2時間
★★☆外部スクリプトの遅延読み込みLCP, INPLCP 0.5〜1秒短縮15分
★★☆不要なuse clientの削除INPJS削減 10〜50KB30分〜1時間
★★☆画像・動画のサイズ属性指定CLSCLS 0に近づく15〜30分
★☆☆重いライブラリの置き換えINPJS削減 50〜300KB1〜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.tsformats: ["image/avif", "image/webp"]と 設定すると、ブラウザの対応状況に応じて最適なフォーマットが配信されます。 AVIFはWebPよりさらに20〜50%圧縮率が高いですが、 エンコード時間が長いため、ビルド時間が気になる場合はWebPのみでも十分です。

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

基本ルールは「インタラクティブ性が必要かどうか」です。useStateuseEffect、イベントハンドラ(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の削除です。

この記事をAIと深掘りする

要約・疑問の解消に。記事のタイトル・URL・参照元を入れた質問文が自動で入力されます。

AUTHOR

立川修平(ぶべ)

ShiftB 校長 / bubekichi inc. 代表

ShiftBを運営する株式会社bubekichiの代表。経理系SaaSの企業でエンジニアを経験後、独立・起業。複数スタートアップでリードエンジニアを務めながら、SNS発信がきっかけで2024年にShiftBを立ち上げる。現在は自社サービスも複数展開中。

RELATED ARTICLES

関連記事

COURSE

AI時代のアプリ開発コース

ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながら学ぶコースです。コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担える状態を目指します。まずは無料相談会でご相談ください。