Advanced (更新: 2026/6/2)

Claude Codeでパフォーマンス最適化:計測からCore Web Vitals改善まで

Claude CodeでWebアプリを計測し、LCP・INP・API遅延を実例コードで改善する実践ガイド。

Claude Codeでパフォーマンス最適化:計測からCore Web Vitals改善まで

Webアプリのパフォーマンス最適化とは、単に「なんとなく速くする」作業ではありません。ユーザーが待たされる時間、操作したあとに画面が反応しない時間、画像や広告でレイアウトが動く不快感、サーバーが余計に使っているCPUやDB接続を、数字で見える形にして減らす作業です。

Claude Codeは、この作業と相性がいいです。ただし「遅いから直して」と丸投げすると、見た目だけの小手先修正になりがちです。先に計測し、仮説を立て、最小の変更を入れ、再計測する。この順番を守ると、Claude Codeはコード調査、修正案、テスト、差分レビューの相棒になります。

この記事では、初心者にもわかる言葉でWeb/App性能改善の考え方を整理し、Claude Codeに渡す指示、コピーして動かせる計測コード、キャッシュ例、落とし穴までまとめます。Core Web Vitalsの定義はweb.dev Core Web Vitals、検査ツールはLighthouse docs、ブラウザ内の計測APIはMDN Performance APIを公式情報として確認してください。

まず「速い」を分解する

Webの速さは1つの数字ではありません。たとえば、最初の大きな画像や見出しが表示されるまでの時間はLCP(Largest Contentful Paint、大きな主要コンテンツが見えるまでの時間)で見ます。クリックやタップに対して画面が次に描画されるまでの反応はINP(Interaction to Next Paint、操作後の反応の重さ)で見ます。読み込み中にボタンや文章がズレる問題はCLS(Cumulative Layout Shift、予期しないレイアウト移動)で見ます。

アプリ側では、APIのp75(75パーセンタイル、100回のうち遅い方から25番目くらいの値)、DBクエリ回数、JavaScriptバンドルサイズ、画像の転送量も重要です。平均値だけを見ると、遅いユーザーが隠れます。Masaが案件で何度か失敗したのは、開発PCのLighthouseスコアだけで「改善した」と判断したことです。低速回線やミドルレンジ端末で見ると、まだ商品一覧が重く、問い合わせフォームの離脱率が下がりませんでした。

flowchart LR
  Measure["計測する"] --> Hypothesis["原因を仮説化"]
  Hypothesis --> Patch["小さく修正"]
  Patch --> Verify["再計測する"]
  Verify --> Keep["効いた変更だけ残す"]

目安は次のように置くと判断しやすくなります。

見るもの何を意味するかまず狙うライン
LCP初期表示の主役が見えるまで2.5秒以内を目標にする
INP操作後の反応の重さ200ms以内を目標にする
CLS読み込み中のズレ0.1以下を目標にする
API p75多くのユーザーが体感するAPI遅延画面ごとにSLOを決める
JS転送量初期表示で読ませるJavaScriptページ単位で差分を見る

Claude Codeに頼む前の材料

Claude Codeに渡す情報は、症状、再現手順、計測値、制約の4つです。曖昧な依頼より、次のような依頼の方が修正の質が上がります。

このリポジトリの /products ページが遅いです。
目的はモバイルのLCPとAPI p75を下げることです。

前提:
- Lighthouse mobile: Performance 58
- LCP: 4.2s
- INP: 180ms
- CLS: 0.04
- /api/products p75: 920ms

依頼:
1. 画像、バンドル、API、DBの順に原因を調査してください。
2. 推測だけで変更せず、確認したファイル名と根拠を出してください。
3. 影響範囲が小さい修正を優先してください。
4. 変更後に確認するコマンドも提案してください。

関連する基礎は、内部記事のClaude Codeデバッグテクニック完全ガイドClaude CodeでReact開発を高速化する方法、画像中心の改善ならClaude Code画像最適化ガイドも合わせて確認すると理解しやすいです。

実行できる計測コード

まずはAPIやページの応答時間を自分で測れるようにします。Node.js 18以降なら、次のファイルをそのまま保存して実行できます。

// measure-url.mjs
import { performance } from "node:perf_hooks";

const url = process.argv[2] ?? "https://example.com/";
const runs = Number(process.argv[3] ?? 5);

async function measureOnce() {
  const start = performance.now();
  const res = await fetch(url, { cache: "no-store" });
  await res.arrayBuffer();
  return {
    status: res.status,
    ms: performance.now() - start,
  };
}

const samples = [];
for (let i = 0; i < runs; i += 1) {
  samples.push(await measureOnce());
}

samples.sort((a, b) => a.ms - b.ms);
const avg = samples.reduce((sum, s) => sum + s.ms, 0) / samples.length;
const p75Index = Math.floor((samples.length - 1) * 0.75);
const p75 = samples[p75Index].ms;

console.table(
  samples.map((sample, index) => ({
    run: index + 1,
    status: sample.status,
    ms: sample.ms.toFixed(1),
  }))
);
console.log(`avg=${avg.toFixed(1)}ms p75=${p75.toFixed(1)}ms`);
node measure-url.mjs http://localhost:3000/api/products 7

この小さなスクリプトは、Claude Codeに「修正前後のAPI p75を比較して」と頼むときの共通言語になります。LighthouseやブラウザDevToolsだけに頼らず、アプリ固有の遅いAPIを数字で切り分けられます。

よくあるユースケース

現実の改善では、1つの銀の弾丸より、複数の小さな詰まりを順番に外すことが多いです。

ユースケースよくある原因Claude Codeに頼むこと
SaaSダッシュボードの初期表示が重い初回に全ウィジェットのAPIを同時実行、巨大なグラフライブラリ重要順に遅延読み込みし、初期表示に必要なデータだけに絞る
ECの商品一覧が遅い商品画像が大きい、在庫・レビュー取得がN+1画像サイズとDB include/selectを見直す
メディア記事のLCPが悪いヒーロー画像が遅い、広告タグが先に走る主要画像を優先し、サードパーティスクリプトを遅延する
管理画面の検索が遅いLIKE検索、インデックス不足、ページングなしクエリ計画とページングを確認する

N+1とは、一覧を1回取得したあとに、各行ごとの追加クエリが何十回も走る状態です。1件なら速くても、100件で急に遅くなります。キャッシュとは、同じ結果を短時間保存して再利用する仕組みです。ただし、ログインユーザー別の情報を共有キャッシュに入れると情報漏えいになります。

キャッシュ改善の実行例

次はExpressで動く、意図的に遅いAPIとキャッシュ済みAPIの比較です。本番ではRedisやCDNを使う場面が多いですが、まず仕組みを掴むにはメモリキャッシュで十分です。

npm init -y
npm install express
node cached-api.mjs
// cached-api.mjs
import express from "express";
import { performance } from "node:perf_hooks";

const app = express();
const cache = new Map();
const ttlMs = 30_000;

async function loadProducts() {
  await new Promise((resolve) => setTimeout(resolve, 800));
  return [
    { id: 1, name: "Starter Plan", price: 1200 },
    { id: 2, name: "Pro Plan", price: 4800 },
  ];
}

async function cached(key, loader) {
  const now = Date.now();
  const hit = cache.get(key);
  if (hit && hit.expiresAt > now) return { data: hit.data, cache: "hit" };

  const data = await loader();
  cache.set(key, { data, expiresAt: now + ttlMs });
  return { data, cache: "miss" };
}

app.get("/api/products/raw", async (_req, res) => {
  const start = performance.now();
  const data = await loadProducts();
  res.json({ cache: "none", ms: performance.now() - start, data });
});

app.get("/api/products/cached", async (_req, res) => {
  const start = performance.now();
  const result = await cached("products", loadProducts);
  res.json({ ...result, ms: performance.now() - start });
});

app.listen(3000, () => {
  console.log("Open http://localhost:3000/api/products/raw");
});

別ターミナルで次を実行します。

node measure-url.mjs http://localhost:3000/api/products/raw 3
node measure-url.mjs http://localhost:3000/api/products/cached 3

Claude Codeに実装を頼むときは、「人気商品APIだけ30秒キャッシュ」「在庫数はキャッシュしない」「ログインユーザーIDをキーに含める」のように、キャッシュしてよい範囲を明確にしてください。

アルゴリズム改善の実行例

UIが重い原因はネットワークだけではありません。大きな配列を毎回二重ループで処理していると、INPが悪化します。次の例は、includesの繰り返しをSetに変えるだけで処理量を減らします。

// compare-lookup.mjs
import { performance } from "node:perf_hooks";

const a = Array.from({ length: 40_000 }, (_, i) => i);
const b = Array.from({ length: 40_000 }, (_, i) => i * 2);

function slowIntersection(left, right) {
  return left.filter((item) => right.includes(item));
}

function fastIntersection(left, right) {
  const rightSet = new Set(right);
  return left.filter((item) => rightSet.has(item));
}

function time(label, fn) {
  const start = performance.now();
  const result = fn();
  const ms = performance.now() - start;
  console.log(`${label}: ${ms.toFixed(1)}ms (${result.length} hits)`);
}

time("slow", () => slowIntersection(a, b));
time("fast", () => fastIntersection(a, b));
node compare-lookup.mjs

Claude Codeには「このコンポーネントの操作時に50msを超える同期処理を探して」「配列処理を計算量の小さい形に変えて」「結果が同じことをテストで示して」と頼むと、過剰なリファクタリングを避けやすくなります。

失敗しやすい落とし穴

1つ目は、Lighthouseスコアだけを追うことです。Lighthouseは研究室のような固定条件の検査で、実ユーザーの端末や通信環境とはズレます。Search Console、RUM(Real User Monitoring、実ユーザー計測)、サーバーログと合わせて見ます。

2つ目は、キャッシュで正しさを壊すことです。価格、在庫、権限、個人情報は、速さより正確性が優先です。キャッシュキー、TTL、削除タイミングを設計せずに導入すると、古い価格や他人のデータを返す事故になります。

3つ目は、useMemomemoを全箇所に入れることです。Reactの再レンダリング対策は、効果がある場所にだけ入れます。計測せずに増やすと、コードが読みにくくなり、依存配列のバグが増えます。

4つ目は、画像最適化の優先順位を間違えることです。ファーストビューの画像には適切なwidthheightsizes、必要なら優先読み込みを使います。一方で、下の方の画像まで全部優先すると、かえってLCPが悪くなります。

5つ目は、バンドル分割のしすぎです。分割は効きますが、細かくしすぎるとリクエストが増えます。Claude Codeバンドル分析Claude Codeコード分割の考え方で、ページ単位の差分を見ながら判断します。

CLAUDE.mdにルールを書く

毎回同じ指示をしないため、プロジェクトのCLAUDE.mdに性能ルールを入れておくと便利です。

## Performance rules
- Before optimizing, record the current metric and target metric.
- Prefer small, measurable changes over broad rewrites.
- Do not introduce shared cache for user-specific data.
- Avoid N+1 queries; use select/include or batching.
- Keep above-the-fold images sized and stable.
- After changes, report commands used for verification.

このルールを入れると、Claude Codeが「速そうな変更」ではなく「測れる変更」を返しやすくなります。特に外注・副業・社内改善の相談では、修正内容よりも、改善前後の証拠を残すことが信頼につながります。

相談・支援が必要な場合

ClaudeCodeLabでは、Claude Codeを使った既存Webアプリの性能棚卸し、Core Web Vitals改善、API/DB遅延の切り分け、改善手順書の作成を支援できます。相談時は、対象URL、主要画面、現在のLighthouse結果、遅いAPIのログ、希望する改善期限を用意してもらえると、初回から具体的な診断に入れます。

この記事で紹介した内容を試した結果

この記事のサンプルを手元で実行すると、意図的に800ms待たせた/api/products/rawは約800ms台の応答になり、/api/products/cachedは2回目以降が数ms台まで下がりました。compare-lookup.mjsも、二重探索よりSetを使う版の方が大きく短縮されます。実案件では数字がここまで綺麗に出るとは限りませんが、「変更前のp75を測る、1点だけ直す、同じ方法で再計測する」という型を守るだけで、Claude Codeの改善提案はかなり実務向けになります。

#Claude Code #パフォーマンス #最適化 #Core Web Vitals #高速化
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。