Agent Skills by ALSEL
汎用ソフトウェア開発⭐ リポ 39,967品質スコア 95/100

performance-optimization

アプリケーションのパフォーマンスを最適化します。パフォーマンス要件がある場合、パフォーマンスの低下が疑われる場合、またはCore Web Vitalsやロード時間の改善が必要な場合に使用してください。プロファイリングによってボトルネックが特定され、修正が必要な場合にも活用できます。

description の原文を見る

Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.

SKILL.md 本文

パフォーマンス最適化

概要

最適化する前に測定します。測定なしのパフォーマンス作業は推測にすぎません。推測は時期尚早な最適化につながり、重要なものを改善することなく複雑さが増すだけです。まずプロファイリングを行い、実際のボトルネックを特定し、修正し、再度測定します。測定が重要であることを証明したものだけを最適化します。

使用時期

  • パフォーマンス要件が仕様に存在する(ロード時間予算、応答時間SLA)
  • ユーザーまたはモニタリングが遅い動作を報告している
  • Core Web Vitalsスコアがしきい値以下である
  • 変更がパフォーマンス低下を招いたと疑われる場合
  • 大規模なデータセットまたは高トラフィックを扱う機能を構築する場合

使用しない場合: 問題の証拠がない場合は最適化しないでください。時期尚早な最適化は、それがもたらすパフォーマンス向上よりも多くのコストを費やす複雑さを追加します。

Core Web Vitalsのターゲット

メトリクス良好改善が必要不良
LCP (Largest Contentful Paint)≤ 2.5s≤ 4.0s> 4.0s
INP (Interaction to Next Paint)≤ 200ms≤ 500ms> 500ms
CLS (Cumulative Layout Shift)≤ 0.1≤ 0.25> 0.25

最適化ワークフロー

1. 測定      → 実際のデータでベースラインを確立する
2. 特定      → 実際のボトルネックを見つける(推測ではない)
3. 修正      → 特定のボトルネックに対処する
4. 検証      → 再度測定し、改善を確認する
5. ガード    → 監視またはテストを追加してリグレッションを防ぐ

ステップ1: 測定

2つの相互補完的なアプローチ — 両方を使用します:

  • 合成テスト(Lighthouse、DevTools Performance タブ): 制御された条件、再現可能。CI リグレッション検出と特定の問題の分離に最適です。
  • RUM(web-vitals ライブラリ、CrUX): 実際の条件での実際のユーザーデータ。修正が実際にユーザー体験を改善したことを検証するために必要です。

フロントエンド:

# 合成テスト: Chrome DevToolsのLighthouse(またはCI)
# Chrome DevTools → Performance タブ → Record
# Chrome DevTools MCP → Performance trace

# RUM: コード内のWeb Vitals ライブラリ
import { onLCP, onINP, onCLS } from 'web-vitals';

onLCP(console.log);
onINP(console.log);
onCLS(console.log);

バックエンド:

# 応答時間ログ記録
# Application Performance Monitoring (APM)
# タイミング付きのデータベースクエリログ

# シンプルなタイミング
console.time('db-query');
const result = await db.query(...);
console.timeEnd('db-query');

測定を開始する場所

症状を使用して、最初に何を測定するかを決めます:

何が遅いのか?
├── 最初のページロード
│   ├── 大きなバンドル? --> バンドルサイズを測定し、コード分割を確認
│   ├── サーバーレスポンスが遅い? --> DevTools ネットワークウォーターフォルでTTFBを測定
│   │   ├── DNS が長い? --> 既知のオリジンに対してdns-prefetch / preconnect を追加
│   │   ├── TCP/TLS が長い? --> HTTP/2 を有効化し、エッジデプロイを確認し、keep-alive を確認
│   │   └── 待機(サーバー)が長い? --> バックエンドをプロファイルし、クエリとキャッシュを確認
│   └── レンダーをブロックするリソース? --> CSS/JS がブロックしているかネットワークウォーターフォルを確認
├── インタラクションが遅い場合
│   ├── クリック時にUIがフリーズ? --> メインスレッドをプロファイルし、長いタスク(>50ms)を探す
│   ├── フォーム入力のラグ? --> 再レンダリングと制御されたコンポーネントのオーバーヘッドを確認
│   └── アニメーションがジャンク? --> レイアウトスラッシング、強制リフロー を確認
├── ナビゲーション後のページ
│   ├── データロード? --> API 応答時間を測定し、ウォーターフォルを確認
│   └── クライアントレンダリング? --> コンポーネントレンダリング時間をプロファイルし、N+1 フェッチを確認
└── バックエンド / API
    ├── 単一エンドポイントが遅い? --> データベースクエリをプロファイルし、インデックスを確認
    ├── すべてのエンドポイントが遅い? --> コネクションプール、メモリ、CPU を確認
    └── 断続的な遅さ? --> ロック競合、GC ポーズ、外部依存を確認

ステップ2: ボトルネックを特定する

カテゴリ別の一般的なボトルネック:

フロントエンド:

症状考えられる原因調査方法
LCP が遅い大きな画像、レンダーをブロックするリソース、遅いサーバーネットワークウォーターフォル、画像サイズを確認
CLS が高い寸法のない画像、遅延して読み込まれるコンテンツ、フォントのシフトレイアウトシフトの属性を確認
INP が悪いメインスレッド上の重いJavaScript、大規模なDOM更新Performance トレースの長いタスクを確認
初期ロードが遅い大きなバンドル、多くのネットワークリクエストバンドルサイズ、コード分割を確認

バックエンド:

症状考えられる原因調査方法
API レスポンスが遅いN+1 クエリ、欠落インデックス、最適化されていないクエリデータベースクエリログを確認
メモリ増加漏れた参照、無制限キャッシュ、大規模ペイロードヒープスナップショット分析
CPU スパイク同期的な重い計算、正規表現のバックトラッキングCPU プロファイリング
高レイテンシキャッシュの欠落、冗長な計算、ネットワークホップスタック全体を通じてリクエストをトレース

ステップ3: 一般的なアンチパターンを修正する

N+1 クエリ(バックエンド)

// 悪い例: N+1 — 所有者のタスクごとに1つのクエリ
const tasks = await db.tasks.findMany();
for (const task of tasks) {
  task.owner = await db.users.findUnique({ where: { id: task.ownerId } });
}

// 良い例: 結合/包含による単一クエリ
const tasks = await db.tasks.findMany({
  include: { owner: true },
});

無制限のデータフェッチ

// 悪い例: すべてのレコードをフェッチ
const allTasks = await db.tasks.findMany();

// 良い例: ページネーション付きで制限
const tasks = await db.tasks.findMany({
  take: 20,
  skip: (page - 1) * 20,
  orderBy: { createdAt: 'desc' },
});

画像最適化の欠落(フロントエンド)

<!-- 悪い例: 寸法なし、フォーマット最適化なし -->
<img src="/hero.jpg" />

<!-- 良い例: ヒーロー / LCP 画像 — アートディレクション + 解像度切り替え、高優先度 -->
<!--
  2つの手法を組み合わせ:
  - アートディレクション(media): ブレークポイントごとに異なるトリミング/構成
  - 解像度切り替え(srcset + sizes): スクリーン密度ごとに正しいファイルサイズ
-->
<picture>
  <!-- モバイル: ポートレートトリミング(8:10) -->
  <source
    media="(max-width: 767px)"
    srcset="/hero-mobile-400.avif 400w, /hero-mobile-800.avif 800w"
    sizes="100vw"
    width="800"
    height="1000"
    type="image/avif"
  />
  <source
    media="(max-width: 767px)"
    srcset="/hero-mobile-400.webp 400w, /hero-mobile-800.webp 800w"
    sizes="100vw"
    width="800"
    height="1000"
    type="image/webp"
  />
  <!-- デスクトップ: ランドスケープトリミング(2:1) -->
  <source
    srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1600.avif 1600w"
    sizes="(max-width: 1200px) 100vw, 1200px"
    width="1200"
    height="600"
    type="image/avif"
  />
  <source
    srcset="/hero-800.webp 800w, /hero-1200.webp 1200w, /hero-1600.webp 1600w"
    sizes="(max-width: 1200px) 100vw, 1200px"
    width="1200"
    height="600"
    type="image/webp"
  />
  <img
    src="/hero-desktop.jpg"
    width="1200"
    height="600"
    fetchpriority="high"
    alt="ヒーロー画像の説明"
  />
</picture>

<!-- 良い例: ページ下部の画像 — 遅延読み込み + 非同期デコード -->
<img
  src="/content.webp"
  width="800"
  height="400"
  loading="lazy"
  decoding="async"
  alt="コンテンツ画像の説明"
/>

不要な再レンダリング(React)

// 悪い例: 毎回レンダリングするときに新しいオブジェクトを作成し、子コンポーネントを再レンダリング
function TaskList() {
  return <TaskFilters options={{ sortBy: 'date', order: 'desc' }} />;
}

// 良い例: 安定した参照
const DEFAULT_OPTIONS = { sortBy: 'date', order: 'desc' } as const;
function TaskList() {
  return <TaskFilters options={DEFAULT_OPTIONS} />;
}

// 高価なコンポーネントにはReact.memoを使用
const TaskItem = React.memo(function TaskItem({ task }: Props) {
  return <div>{/* 高価なレンダリング */}</div>;
});

// 高価な計算にはuseMemoを使用
function TaskStats({ tasks }: Props) {
  const stats = useMemo(() => calculateStats(tasks), [tasks]);
  return <div>{stats.completed} / {stats.total}</div>;
}

大規模なバンドルサイズ

// モダンなバンドラー(Vite、webpack 5+)は、依存関係がESMを提供し、
// package.jsonで`sideEffects: false`でマークされている場合、
// 自動的に名前付きインポートでツリーシェイキングを処理します。
// インポートスタイルを変更する前にプロファイルします — 実際のゲインはスプリッティングと遅延ロードから来ます。

// 良い例: 重い、めったに使用されない機能の動的インポート
const ChartLibrary = lazy(() => import('./ChartLibrary'));

// 良い例: Suspense にラップされたルートレベルのコード分割
const SettingsPage = lazy(() => import('./pages/Settings'));

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <SettingsPage />
    </Suspense>
  );
}

キャッシングの欠落(バックエンド)

// 頻繁に読まれ、めったに変更されないデータをキャッシュ
const CACHE_TTL = 5 * 60 * 1000; // 5 分
let cachedConfig: AppConfig | null = null;
let cacheExpiry = 0;

async function getAppConfig(): Promise<AppConfig> {
  if (cachedConfig && Date.now() < cacheExpiry) {
    return cachedConfig;
  }
  cachedConfig = await db.config.findFirst();
  cacheExpiry = Date.now() + CACHE_TTL;
  return cachedConfig;
}

// 静的アセット用のHTTPキャッシングヘッダー
app.use('/static', express.static('public', {
  maxAge: '1y',           // 1年間キャッシュ
  immutable: true,        // 再検証しない(ファイル名でコンテンツハッシングを使用)
}));

// API レスポンス用のCache-Control
res.set('Cache-Control', 'public, max-age=300'); // 5 分

パフォーマンス予算

予算を設定して強制します:

JavaScript バンドル: < 200KB gzip(初期ロード)
CSS: < 50KB gzip
画像: < 200KB per image(上部)
フォント: < 100KB total
API レスポンス時間: < 200ms (p95)
Interactive までの時間: < 3.5s on 4G
Lighthouse Performance スコア: ≥ 90

CI で強制:

# バンドルサイズチェック
npx bundlesize --config bundlesize.config.json

# Lighthouse CI
npx lhci autorun

関連項目

詳細なパフォーマンスチェックリスト、最適化コマンド、アンチパターンリファレンスについては、references/performance-checklist.md を参照してください。

一般的な言い訳

言い訳現実
「後で最適化します」パフォーマンス負債は複利的に増えます。明らかなアンチパターンは今修正し、マイクロ最適化は後回しにします。
「私のマシンでは速い」あなたのマシンはユーザーのものではありません。代表的なハードウェアとネットワークでプロファイルします。
「この最適化は明白です」測定しないと、知ることはできません。まずプロファイルします。
「ユーザーは100msに気付きません」研究によると、100ms の遅延はコンバージョンレートに影響を与えます。ユーザーはあなたが思うより多くに気付きます。
「フレームワークがパフォーマンスを処理します」フレームワークはいくつかの問題を防ぎますが、N+1 クエリや過度なバンドルは修正できません。

赤い旗

  • プロファイリングデータなしの最適化
  • データフェッチのN+1 クエリパターン
  • ページネーションなしのリストエンドポイント
  • 寸法、遅延ロード、または応答サイズのない画像
  • レビューなしのバンドルサイズの増加
  • 本番環境でのパフォーマンスモニタリングなし
  • React.memouseMemo がいたるところ(過度な使用は使用不足と同じくらい悪い)

検証

パフォーマンス関連の変更後:

  • 変更前と変更後の測定が存在する(具体的な数値)
  • 特定のボトルネックが特定され、対処されている
  • Core Web Vitals が「良好」のしきい値内にある
  • バンドルサイズが大幅に増加していない
  • 新しいデータフェッチコードにN+1 クエリがない
  • パフォーマンス予算が CI でパス(設定されている場合)
  • 既存テストが引き続きパス(最適化が動作を破壊していない)

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
addyosmani
リポジトリ
addyosmani/agent-skills
ライセンス
MIT
最終更新
2026/5/10

Source: https://github.com/addyosmani/agent-skills / ライセンス: MIT

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: addyosmani · addyosmani/agent-skills · ライセンス: MIT