nextjs-performance
Next.jsアプリのパフォーマンス最適化に特化したスキルで、Core Web Vitals(LCP・INP・CLS)の改善、`next/image`・`next/font`の最適化、`unstable_cache`や`revalidateTag`を用いたキャッシュ設定、Client ComponentのServer Component化、Suspenseストリーミングの実装、バンドルサイズの分析・削減などに対応します。Next.js 16 + React 19のパターンをサポートしており、Next.jsアプリの速度・配信効率を向上させたい場面で活用してください。
description の原文を見る
Expert Next.js performance optimization skill covering Core Web Vitals, image/font optimization, caching strategies, streaming, bundle optimization, and Server Components best practices. Use when optimizing Next.js applications for Core Web Vitals (LCP, INP, CLS), implementing next/image and next/font, configuring caching with unstable_cache and revalidateTag, converting Client Components to Server Components, implementing Suspense streaming, or analyzing and reducing bundle size. Supports Next.js 16 + React 19 patterns.
SKILL.md 本文
Next.js パフォーマンス最適化
Core Web Vitals、最新パターン、ベストプラクティスに焦点を当てた Next.js アプリケーション最適化の専門ガイダンス。
概要
このスキルは Next.js アプリケーションの最適化に関する包括的なガイダンスを提供します。Core Web Vitals 最適化(LCP、INP、CLS)、最新の React パターン、Server Components、キャッシング戦略、バンドルサイズ最適化技法をカバーしています。React/Next.js に既に精通し、プロダクショングレードの最適化を実装したい開発者向けに設計されています。
使用場面
Next.js アプリケーションで作業しており、以下の対応が必要な場合にこのスキルを使用します:
- Core Web Vitals(LCP、INP、CLS)を最適化してパフォーマンスと SEO を向上させる
next/imageで画像最適化を実装して読み込み速度を上げるnext/fontでフォント最適化を設定してレイアウトシフトを排除するunstable_cache、revalidateTag、ISR を使用してキャッシング戦略を設定する- Client Components を Server Components に変換してバンドルサイズを削減する
- Suspense ストリーミングを実装してプログレッシブなページ読み込みを行う
- コード分割と動的インポートでバンドルサイズを分析・削減する
- メタデータと SEO を設定して検索エンジンの可視性を向上させる
- API ルートハンドラーを最適化してパフォーマンスを向上させる
- Next.js 16 と React 19 の最新パターンを適用する
カバレッジ領域
- Core Web Vitals 最適化(LCP、INP、CLS)
- 画像最適化 with
next/image - フォント最適化 with
next/font - キャッシング戦略(
unstable_cache、revalidateTag、ISR) - Server Components パターンと Client から Server への変換
- ストリーミングと Suspense によるプログレッシブ読み込み
- バンドル最適化 とコード分割
- メタデータと SEO 設定
- ルートハンドラー 最適化
- Next.js 16 + React 19 パターン
使用方法
開始前に
- 現在のパフォーマンスを分析 (Lighthouse を使用)
- ボトルネックを特定 - Chrome DevTools または PageSpeed Insights で Core Web Vitals を確認
- 最適化の優先順位を決定:
- LCP の問題 → 画像、フォントに焦点を当てる
- INP の問題 → JS を削減、Server Components を使用
- CLS の問題 → サイズを追加、next/font を使用
このスキルの使用方法
-
最適化する領域に基づいて関連の参照ファイルを読み込む:
- 画像の問題 →
references/image-optimization.md - フォント/レイアウトシフト →
references/font-optimization.md - キャッシング →
references/caching-strategies.md - コンポーネントアーキテクチャ →
references/server-components.md
- 画像の問題 →
-
一般的な最適化のクイックパターンを従う
-
既存のコードを改善するために変更前後の変換を適用
-
変更後 Lighthouse で改善を検証
コアプリンシパル
- Server Components を優先 - 必要な場合(ブラウザ API、インタラクティビティ)のみ 'use client' を使用
- コンポーネントはできるだけ低く読み込む - Client Components をリーフノードに保つ
- Suspense 境界を使用 - ストリーミングとプログレッシブ読み込みを有効化
- 適切にキャッシュ - 粒度の細かい再検証のためタグを使用
- 測定してから実装 - 常に実際のメトリクスで改善を検証
例
例 1: Client Component を Server Component に変換
変更前 (useEffect 付き Client Component):
'use client'
import { useEffect, useState } from 'react'
export default function ProductList() {
const [products, setProducts] = useState([])
useEffect(() => {
fetch('/api/products').then(r => r.json()).then(setProducts)
}, [])
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
変更後 (直接データアクセスの Server Component):
import { db } from '@/lib/db'
export default async function ProductList() {
const products = await db.product.findMany()
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
例 2: LCP のための画像最適化
import Image from 'next/image'
export function Hero() {
return (
<div className="relative w-full h-[600px]">
<Image
src="/hero.jpg"
alt="Hero"
fill
priority // LCP のための遅延読み込みを無効化
sizes="100vw"
className="object-cover"
/>
</div>
)
}
例 3: キャッシング戦略を実装
import { unstable_cache, revalidateTag } from 'next/cache'
// キャッシュされたデータ関数
const getProducts = unstable_cache(
async () => db.product.findMany(),
['products'],
{ revalidate: 3600, tags: ['products'] }
)
// ミューテーション時に再検証
export async function createProduct(data: FormData) {
'use server'
await db.product.create({ data })
revalidateTag('products')
}
例 4: 最適化されたフォントを設定
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
})
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.variable}>
<body className={`${inter.className} antialiased`}>
{children}
</body>
</html>
)
}
例 5: Suspense ストリーミングを実装
import { Suspense } from 'react'
export default function Page() {
return (
<>
<header>スタティックコンテンツ(即座に表示)</header>
<Suspense fallback={<ProductSkeleton />}>
<ProductList /> {/* 準備完了時にストリーム配信 */}
</Suspense>
<Suspense fallback={<ReviewsSkeleton />}>
<Reviews /> {/* 独立したストリーミング */}
</Suspense>
</>
)
}
参照ドキュメント
特定の領域で作業する際にこれらの参照を読み込みます:
| トピック | 参照ファイル |
|---|---|
| Core Web Vitals | references/core-web-vitals.md |
| 画像最適化 | references/image-optimization.md |
| フォント最適化 | references/font-optimization.md |
| キャッシング戦略 | references/caching-strategies.md |
| Server Components | references/server-components.md |
| ストリーミング/Suspense | references/streaming-suspense.md |
| バンドル最適化 | references/bundle-optimization.md |
| メタデータ/SEO | references/metadata-seo.md |
| API ルート | references/api-routes.md |
| Next.js 16 パターン | references/nextjs-16-patterns.md |
一般的な変換
| 変更前 | 変更後 | メリット |
|---|---|---|
useEffect + fetch | Server Component での直接 async | -70% JS、TTFB の高速化 |
データの useState | 直接 DB アクセスの Server Component | コード簡潔化、ハイドレーション不要 |
| クライアント側フェッチ | unstable_cache または ISR | 繰り返し読み込み高速化 |
img タグ | next/image | 最適化フォーマット、遅延読み込み |
| CSS フォント インポート | next/font | CLS ゼロ、自動最適化 |
| ヘビーコンポーネントの静的インポート | dynamic() | 初期バンドルサイズ削減 |
ベストプラクティス
画像
- すべての画像に
next/imageを使用 - LCP 画像のみに
priorityを追加 widthとheightを提供、またはfillとsizesを使用- UX 向上のため
placeholder="blur"を使用 - next.config.js で remotePatterns を設定
フォント
- CSS インポートの代わりに
next/fontを使用 - サイズ削減のため
subsetsを指定 - 即座のテキスト描画のため
display: 'swap'を使用 variableオプションで CSS 変数を作成- Tailwind を設定して CSS 変数を使用
キャッシング
- 高コストのクエリを
unstable_cacheでキャッシュ - 粒度の細かい制御のため意味のあるキャッシュタグを使用
- 動的コンテンツのためにオンデマンド再検証を実装
- データ変更頻度に基づいて TTL を設定
- ルートレベルの無効化のため revalidatePath を使用
コンポーネント
- 可能な限り Client Components を Server Components に変換
- Client Components をリーフレベルに保つ
- プログレッシブ読み込みのため Suspense 境界を使用
- 適切なロード状態を実装
- 下部折り込み以下のヘビーコンポーネントは
dynamic()を使用
バンドル
dynamic()でヘビーコンポーネントを遅延読み込み- より良いツリーシェイキングのため名前付きエクスポートを使用
@next/bundle-analyzerでバンドルを定期的に分析- CommonJS より ESM パッケージを優先
- 大規模ライブラリの場合 modularizeImports を使用
制約と警告
Server Components の制限事項
- ブラウザ API(window、localStorage、document)を使用できない
- React フック(useState、useEffect、useContext)を使用できない
- イベントハンドラー(onClick、onSubmit)を使用できない
- ssr: false の動的インポートを使用できない
画像最適化の制約
priorityはフォールド上の画像にのみ使用すべき- 外部画像は next.config.js で設定が必要
fillを使用しない限りwidthとheightが必須- アニメーション GIF はデフォルトで最適化されない
キャッシングの考慮事項
- キャッシュタグは手動で無効化する必要がある
- データキャッシュは開発環境ではリクエストごと
- エッジランタイムは異なるキャッシング動作を持つ
- ユーザー固有のデータのキャッシュに注意
バンドルサイズの警告
- 動的インポートはクリティカルコンテンツの場合 SEO に影響する可能性がある
- ツリーシェイキングは適切な ES モジュール使用が必須
- 一部ライブラリはツリーシェイキング不可(バレルエクスポートを避ける)
- Client Components はバンドルサイズを増加させる - 慎重に使用
Next.js 16 + React 19 固有事項
非同期 Params
// Next.js 15+ では params は Promise
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const post = await fetchPost(slug)
return <article>{post.content}</article>
}
Promise 用の use() フック
'use client'
import { use, Suspense } from 'react'
function Comments({ promise }: { promise: Promise<Comment[]> }) {
const comments = use(promise) // 解決まで中断
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>
}
UI 更新用の useOptimistic
'use client'
import { useOptimistic } from 'react'
export function TodoList({ todos }: { todos: Todo[] }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo: Todo) => [...state, newTodo]
)
async function addTodo(formData: FormData) {
const text = formData.get('text') as string
addOptimisticTodo({ id: crypto.randomUUID(), text, completed: false })
await createTodo(text)
}
return (
<form action={addTodo}>
<input name="text" />
{optimisticTodos.map(todo => <div key={todo.id}>{todo.text}</div>)}
</form>
)
}
バンドル分析
# アナライザーをインストール
npm install --save-dev @next/bundle-analyzer
# 分析を実行
ANALYZE=true npm run build
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
modularizeImports: {
'lodash': { transform: 'lodash/{{member}}' },
},
})
パフォーマンス チェックリスト
- すべての画像が
next/imageを使用し適切なサイズを指定している - LCP 画像に
priority属性がある - フォントが
next/fontを使用し subsets を指定している - Server Components が可能な限り使用されている
- Client Components がリーフレベルのみに配置されている
- データ取得のための Suspense 境界がある
- キャッシングが高コスト操作のために設定されている
- バンドルが重複について分析されている
- ヘビーコンポーネントが遅延読み込みされている
- 変更前後の Lighthouse スコアが検証されている
一般的な間違い
// ❌ やってはいけないこと: useEffect でフェッチ
'use client'
useEffect(() => { fetch('/api/data').then(...) }, [])
// ✅ やるべきこと: Server Component で直接フェッチ
const data = await fetch('/api/data')
// ❌ やってはいけないこと: 画像のサイズを指定しない
<Image src="/photo.jpg" />
// ✅ やるべきこと: 常にサイズを指定
<Image src="/photo.jpg" width={800} height={600} />
// ❌ やってはいけないこと: すべての画像に priority を使用
<Image src="/photo1.jpg" priority />
<Image src="/photo2.jpg" priority />
// ✅ やるべきこと: LCP のみに priority を使用
<Image src="/hero.jpg" priority />
<Image src="/photo.jpg" loading="lazy" />
// ❌ やってはいけないこと: すべてを同じ TTL でキャッシュ
{ revalidate: 3600 }
// ✅ やるべきこと: データ変更頻度に TTL を合わせる
{ revalidate: 86400 } // カテゴリはめったに変わらない
{ revalidate: 60 } // コメントはよく変わる
外部リソース
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。