mcpField
N
nextjs-optimization

nextjs-optimization

github.com/atman36開発678 回インストール40 週間前に更新
リポジトリ

nextjs-optimization について

Next.js アプリの改善を支援するスキルです。レンダリング、データ取得、キャッシュ、バンドル、SEO、Core Web Vitals の確認や測定方法を扱い、開発時やデプロイ前に利用できます。

主な機能

  1. 01レンダリング戦略の指針
  2. 02画像・バンドルの最適化
  3. 03データ取得とキャッシュ
  4. 04メタデータと SEO の確認
  5. 05Lighthouse と Web Vitals の指針

活用シーン

  1. 01デプロイ前の Next.js アプリ確認
  2. 02ページ表示の遅さの調査
  3. 03キャッシュとデータ取得の改善

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/atman36/ai-vibe-prompts --skill nextjs-optimization

インストール後、Claude Code で/nextjs-optimizationを入力して読み込まれたか確認します。

詳細

Next.js 15 最適化スキル

目的

Next.js アプリケーションを最適化し、以下を実現します。

  • Core Web Vitals で満点を獲得する(LCP < 2.5s、FID < 100ms、CLS < 0.1)
  • ページ読み込みを高速化し、最適なレンダリング戦略を採用する
  • データ取得とキャッシュを効率化する
  • 本番環境に対応したビルド設定にする
  • SEO とアクセシビリティを優れた状態にする

このスキルを使用するタイミング

次の場合に自動で呼び出します。

  • プロジェクトで Next.js を使用している(依存関係に next がある場合に検出)
  • ユーザーが「最適化」「パフォーマンス」「遅い」「Core Web Vitals」に言及したとき
  • 本番環境へのデプロイ前
  • 新しい機能やページの追加後
  • ユーザーが Next.js 固有の改善を依頼したとき

前提条件の確認

ツール:Read、Grep

  1. Next.js のバージョンを確認:

    # Read package.json
    # Check for "next": "^15.0.0" or higher
    
  2. App Router を検出(Next.js 13 以降):

    • app/ ディレクトリを確認
    • layout.tsx、page.tsx ファイルを確認
  3. Pages Router を検出(レガシー):

    • pages/ ディレクトリを確認
    • App Router への移行を提案

最適化のカテゴリ

1. レンダリング戦略の最適化

目標:各ページ/コンポーネントに最適なレンダリングを選択します

ツール:Read、Grep、Edit

1.1 サーバーコンポーネント(App Router のデフォルト)

使用するケース:

  • API/データベースからのデータ取得
  • 負荷の高い計算
  • バックエンドリソースへのアクセス

パターン:

// app/dashboard/page.tsx
export default async function DashboardPage() {
  const data = await fetchData(); // Runs on server
  return <Dashboard data={data} />;
}

違反箇所の確認:

# Search for "use client" in components that don't need it
grep -r "use client" app/ | grep -v "onClick\|useState\|useEffect"
1.2 クライアントコンポーネント

使用するケース:

  • インタラクティブな UI(onClick、フォーム)
  • ブラウザー API(window、localStorage)
  • React フック(useState、useEffect)

パターン:

// app/components/Counter.tsx
'use client';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

最適化:クライアントコンポーネントは小さく保ち、リーフノードにします

1.3 静的生成(SSG)

使用するケース:

  • 頻繁には変更されないコンテンツ
  • マーケティングページ、ブログ、ドキュメント

パターン:

export const revalidate = 3600; // Revalidate every hour

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
  return <Article post={post} />;
}
1.4 ISR による動的レンダリング

使用するケース:

  • 定期的に変更されるコンテンツ
  • E コマースの商品、ユーザープロフィール

パターン:

export const revalidate = 60; // Revalidate every minute

export async function generateStaticParams() {
  const products = await getProducts();
  return products.map((p) => ({ slug: p.slug }));
}
2. 画像の最適化

目標:パフォーマンスと Core Web Vitals のために画像を最適化します

ツール:Grep、Read、Edit

2.1 Next.js Image コンポーネントを使用する

最適化されていない画像を検索:

grep -rn "<img " app/ src/

次のように置き換える:

import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero image"
  width={1200}
  height={600}
  priority // For above-the-fold images
  placeholder="blur" // Optional blur-up effect
/>
2.2 画像ドメインを設定する

next.config.js を読み込む:

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
      },
    ],
    formats: ['image/avif', 'image/webp'], // Modern formats
  },
};
2.3 遅延読み込み戦略
  • priority:ファーストビューの画像(LCP 候補)
  • loading="lazy":ファーストビューより下の画像(デフォルト)
3. フォントの最適化

目標:FOUT/FOIT をなくし、フォントの読み込みを改善します

ツール:Read、Edit

3.1 next/font を使用する

パターン:

// app/layout.tsx
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // Prevent FOIT
  variable: '--font-inter',
});

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={inter.variable}>
      <body>{children}</body>
    </html>
  );
}
3.2 セルフホストフォント
import localFont from 'next/font/local';

const customFont = localFont({
  src: './fonts/CustomFont.woff2',
  display: 'swap',
  variable: '--font-custom',
});
4. データ取得の最適化

目標:ウォーターフォールを最小限に抑え、キャッシュを最適化します

ツール:Read、Grep、Edit

4.1 並列データ取得

アンチパターン(逐次):

const user = await getUser();
const posts = await getPosts(user.id); // Waits for user

最適化後(並列):

const [user, posts] = await Promise.all([
  getUser(),
  getPosts(),
]);
4.2 Suspense によるストリーミング

パターン:

import { Suspense } from 'react';

export default function Page() {
  return (
    <>
      <Header />
      <Suspense fallback={<Skeleton />}>
        <SlowComponent />
      </Suspense>
      <Footer />
    </>
  );
}
4.3 キャッシュ設定
// Aggressive caching
fetch('https://api.example.com/data', {
  next: { revalidate: 3600 }, // Cache for 1 hour
});

// No caching
fetch('https://api.example.com/data', {
  cache: 'no-store', // Always fresh
});

// Opt out of caching
export const dynamic = 'force-dynamic';
5. バンドルの最適化

目標:JavaScript バンドルのサイズを削減します

ツール:Bash、Read、Edit

5.1 バンドルを分析する
# Add to package.json scripts
npm run build
npx @next/bundle-analyzer
5.2 動的インポート

大きなコンポーネントを検索:

find app -name "*.tsx" -exec wc -l {} \; | sort -rn | head -10

動的インポートで分割する:

import dynamic from 'next/dynamic';

const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Skeleton />,
  ssr: false, // Skip SSR if not needed
});
5.3 ツリーシェイキング

バレルエクスポートを確認:

grep -rn "export \* from" app/

個別のインポートに置き換える:

// Anti-pattern
import { Button, Card, Modal } from '@/components';

// Optimized
import { Button } from '@/components/Button';
6. メタデータと SEO

目標:SEO とソーシャル共有を最適化します

ツール:Read、Edit

6.1 静的メタデータ
// app/layout.tsx
export const metadata = {
  title: {
    default: 'My App',
    template: '%s | My App',
  },
  description: 'Description for SEO',
  openGraph: {
    title: 'My App',
    description: 'Description for social sharing',
    images: ['/og-image.jpg'],
  },
  twitter: {
    card: 'summary_large_image',
  },
};
6.2 動的メタデータ
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      images: [post.ogImage],
    },
  };
}
7. 本番環境の設定

目標:本番環境向けに next.config.js を最適化します

ツール:Read、Edit

7.1 必須の設定
// next.config.js
module.exports = {
  reactStrictMode: true,
  poweredByHeader: false, // Security
  compress: true, // Gzip compression
  
  // Compiler optimizations
  compiler: {
    removeConsole: process.env.NODE_ENV === 'production',
  },
  
  // Image optimization
  images: {
    formats: ['image/avif', 'image/webp'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
  },
  
  // React Compiler (Next.js 15)
  experimental: {
    reactCompiler: true,
  },
};
7.2 Turbopack(開発環境)
// package.json
{
  "scripts": {
    "dev": "next dev --turbo"
  }
}
8. Core Web Vitals の最適化

目標:Lighthouse で満点を獲得します

ツール:Bash、Grep、Edit

8.1 LCP(最大コンテンツの描画) < 2.5s

最適化:

  • ヒーロー画像に priority を使用する
  • 重要なリソースをプリロードする
  • ファーストビューのコンテンツをサーバーサイドでレンダリングする
// Preload critical resources
<link rel="preload" href="/hero.jpg" as="image" />
8.2 FID(初回入力遅延) < 100ms

最適化:

  • JavaScript の実行を最小限に抑える
  • 重要でないコードには動的インポートを使用する
  • サードパーティスクリプトの実行を遅らせる
import Script from 'next/script';

<Script
  src="https://analytics.example.com"
  strategy="lazyOnload" // Load after page interactive
/>
8.3 CLS(Cumulative Layout Shift)< 0.1

最適化:

  • 画像の寸法を必ず指定します
  • 動的コンテンツ用のスペースを確保します
  • font-display: swap を使用します
/* Reserve space for ads/banners */
.ad-container {
  min-height: 250px;
}
9. キャッシュ戦略

目標:キャッシュヒットを最大化し、サーバー負荷を最小限に抑えます

ツール:Read、Edit

9.1 ルートセグメントの設定
// app/dashboard/page.tsx
export const revalidate = 3600; // ISR every hour
export const dynamic = 'auto'; // Automatic optimization
export const fetchCache = 'force-cache'; // Aggressive caching
9.2 データキャッシュ
// Deduplicated and cached automatically
const user = await fetch('https://api.example.com/user');

// Revalidate tag-based
export const revalidate = 60;
export const tags = ['user', 'profile'];
10. 監視と測定

目標:パフォーマンスを継続的に追跡します

ツール:Bash、WebSearch

10.1 Web Vitals のレポートを追加する
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <SpeedInsights />
      </body>
    </html>
  );
}
10.2 Lighthouse CI
# Run Lighthouse
npx lighthouse http://localhost:3000 --view

# Check Core Web Vitals
npm run build
npm run start
npx lighthouse http://localhost:3000 --only-categories=performance

最適化チェックリスト

このチェックリストに沿って確認します:

  • すべての画像で、適切な寸法を指定した next/image を使用している
  • フォントで display: swap を指定した next/font を使用している
  • デフォルトでサーバーコンポーネントを使用している(不要な 'use client' を使用していない)
  • クライアントコンポーネントが末端ノードであり、最小限に抑えられている
  • 可能な場合、データ取得に並列リクエストを使用している
  • 遅いコンポーネントが <Suspense> でラップされている
  • 大きなコンポーネントで動的インポートを使用している
  • すべてのページでメタデータが設定されている
  • next.config.js で本番環境向けの最適化が行われている
  • React Compiler が有効になっている(Next.js 15)
  • バンドルを分析し、最適化している
  • Core Web Vitals が目標値を満たしている(Lighthouse でテスト)

出力形式

# Next.js Optimization Report

## Current Status
- **Next.js Version**: 15.0.3
- **Rendering**: App Router
- **React Version**: 19.0.0

## Issues Found

### 🔴 Critical (3)
1. **Unoptimized Images**: 12 `<img>` tags found
   - Files: `app/page.tsx`, `app/about/page.tsx`
   - Fix: Replace with `next/image`

2. **Large Client Bundle**: 342 KB (target: < 200 KB)
   - Cause: Heavy chart library loaded synchronously
   - Fix: Use dynamic import for `Chart` component

3. **Missing Font Optimization**: Using Google Fonts via <link>
   - Fix: Migrate to `next/font/google`

### 🟡 Warnings (2)
1. **Sequential Data Fetching**: Waterfall detected in `app/dashboard/page.tsx`
2. **No Metadata**: Missing OpenGraph tags on 5 pages

## Optimizations Applied

✅ Enabled React Compiler in next.config.js
✅ Added image optimization config
✅ Configured proper cache headers
✅ Added Suspense boundaries to slow routes

## Performance Impact (Estimated)

- **Load Time**: 3.2s → 1.8s (-44%)
- **Bundle Size**: 342 KB → 198 KB (-42%)
- **LCP**: 3.1s → 2.3s (✅ Good)
- **FID**: 85ms → 45ms (✅ Good)
- **CLS**: 0.15 → 0.05 (✅ Good)

## Next Steps

1. Replace 12 `<img>` tags with `next/image`
2. Split Chart component with dynamic import
3. Add metadata to 5 pages
4. Run Lighthouse to verify improvements

ベストプラクティス

  1. サーバー優先の考え方:デフォルトでサーバーコンポーネントを使用します
  2. プログレッシブエンハンスメント:低速なネットワークを前提に構築します
  3. 推測ではなく測定:Lighthouse と Web Vitals を使用します
  4. 積極的なキャッシュ:適切に再検証することも忘れないでください
  5. 段階的な最適化:まず重大な問題を修正します

他のスキルとの連携

  • codebase-analysis - Next.js のプロジェクトとバージョンを検出します
  • quality-gates - ビルドを実行し、リグレッションがないことを確認します
  • react-patterns - React 19 のベストプラクティスを徹底します
  • testing-strategy - パフォーマンステストを追加します

避けるべき一般的なアンチパターン

❌ トップレベルで 'use client' を使用する ❌ 画像の寸法を指定しない ❌ 同期的なデータ取得 ❌ コンポーネントライブラリ全体を読み込む ❌ Suspense 境界がない ❌ Core Web Vitals を無視する

バージョン履歴

  • 1.0.0 (2025-01-03):App Router に重点を置いた Next.js 15 向けの初期スキル

コメント