Claude Code Plugins

Community-maintained marketplace

Feedback

nextjs-development

@Gaku52/claude-code-skills
1
0

Next.js App Router開発ガイド。Server Components、ルーティング、データフェッチング、キャッシング、デプロイなど、Next.js開発のベストプラクティス。

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name nextjs-development
description Next.js App Router開発ガイド。Server Components、ルーティング、データフェッチング、キャッシング、デプロイなど、Next.js開発のベストプラクティス。

Next.js Development Skill

📋 目次

基礎編(このファイル)

  1. 概要
  2. いつ使うか
  3. App Router基礎
  4. Server Components vs Client Components
  5. データフェッチング
  6. キャッシング戦略
  7. 実践例
  8. アンチパターン
  9. Agent連携

詳細ガイド(完全版)

  1. Server Components完全ガイド - 23,000文字
  2. データフェッチング戦略完全ガイド - 28,000文字
  3. キャッシング&リバリデーション完全ガイド - 26,000文字

概要

このSkillは、Next.js App Router開発をカバーします:

  • App Router - ファイルベースルーティング
  • Server Components - サーバーサイドレンダリング
  • データフェッチング - fetch, Prisma, ORMs
  • キャッシング - 自動キャッシュ、revalidate
  • API Routes - RESTful API
  • デプロイ - Vercel, 自己ホスティング

📚 詳細ガイド

プロダクションレベルの実装を学ぶには、以下の完全ガイドを参照してください:

1. Server Components完全ガイド

23,000文字 | 完全なTypeScript実装例 | 実測値データ付き

  • Server Components vs Client Componentsの完全解説
  • 使い分け戦略とパターン(10以上)
  • 実測パフォーマンス比較(バンドルサイズ -81.7%、データフェッチ -82.7%)
  • よくある4つの間違いと解決策
  • 実践的なブログアプリ・ECサイトの完全実装

2. データフェッチング戦略完全ガイド

28,000文字 | Prisma統合 | Server Actions実装

  • fetch APIの完全活用(5パターン)
  • Prisma/ORMとの統合(CRUD、トランザクション、集計クエリ)
  • 並列・直列フェッチングの最適化
  • エラーハンドリングとリトライ機構
  • 実測値に基づく改善効果(並列実行 -66.7%、キャッシング -98.2%)

3. キャッシング&リバリデーション完全ガイド

26,000文字 | 4つのキャッシュ階層 | Webhook連携

  • キャッシュの4つの階層(Request Memoization、Data Cache、Full Route Cache、Router Cache)
  • 時間ベース、オンデマンド、タグベースリバリデーション
  • キャッシュ戦略パターン(5パターン)
  • CMSとのWebhook連携実装
  • 実測データ(キャッシュヒット -98.2%、TTFB -97.9%)

合計: 77,000文字 | 30以上の完全実装例 | 実プロジェクトの測定データ


🎓 学習パス

初心者向け

  1. このファイルで基礎を理解
  2. Server Components完全ガイドで実装方法を習得
  3. 簡単なブログアプリを作成

中級者向け

  1. データフェッチング戦略完全ガイドでPrisma統合を学習
  2. キャッシング&リバリデーション完全ガイドで最適化手法を習得
  3. ECサイトやダッシュボードを作成

上級者向け

  1. 全ての詳細ガイドを参照しながら、大規模アプリケーションを設計
  2. パフォーマンス測定とチューニング
  3. CMSとのWebhook連携やカスタムキャッシュ戦略を実装

いつ使うか

🎯 必須のタイミング

  • 新規Next.jsプロジェクト作成時
  • ページ・レイアウト追加時
  • API Route追加時
  • データフェッチング実装時

App Router基礎

ファイルベースルーティング

app/
├── page.tsx                  # / (ルート)
├── about/page.tsx            # /about
├── blog/
│   ├── page.tsx              # /blog
│   └── [slug]/page.tsx       # /blog/hello-world
├── dashboard/
│   ├── layout.tsx            # /dashboard のレイアウト
│   ├── page.tsx              # /dashboard
│   └── settings/page.tsx     # /dashboard/settings
└── api/
    └── users/route.ts        # /api/users

ページの作成

// app/page.tsx(ルートページ)
export default function Home() {
  return (
    <main>
      <h1>Welcome</h1>
    </main>
  )
}

レイアウトの作成

// app/layout.tsx(ルートレイアウト)
export const metadata = {
  title: 'My App',
  description: 'App description',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja">
      <body>
        <nav>ナビゲーション</nav>
        {children}
        <footer>フッター</footer>
      </body>
    </html>
  )
}

// app/dashboard/layout.tsx(ネストレイアウト)
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className="flex">
      <aside>サイドバー</aside>
      <main>{children}</main>
    </div>
  )
}

動的ルート

// app/blog/[slug]/page.tsx
interface PageProps {
  params: { slug: string }
  searchParams: { [key: string]: string | string[] | undefined }
}

export default function BlogPost({ params }: PageProps) {
  return <h1>Post: {params.slug}</h1>
}

// 静的生成用
export async function generateStaticParams() {
  const posts = await getPosts()

  return posts.map((post) => ({
    slug: post.slug,
  }))
}

Server Components vs Client Components

Server Components(デフォルト)

// app/posts/page.tsx
// ✅ Server Component(デフォルト)

async function getPosts() {
  const res = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600 } // 1時間キャッシュ
  })
  return res.json()
}

export default async function PostsPage() {
  const posts = await getPosts() // 直接await可能

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

メリット:

  • サーバーで実行(クライアントバンドル削減)
  • 直接DBアクセス可能
  • 環境変数を安全に使用可能

Client Components

// components/Counter.tsx
'use client' // ← 必須

import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  )
}

使用するタイミング:

  • useState, useEffect等のHooksを使う
  • イベントハンドラー(onClick等)
  • ブラウザAPI(localStorage等)

混在パターン

// app/page.tsx(Server Component)
import { Counter } from '@/components/Counter' // Client Component

async function getInitialCount() {
  // サーバーでデータ取得
  return 42
}

export default async function Home() {
  const initialCount = await getInitialCount()

  return (
    <div>
      <h1>Server Component</h1>
      <Counter initialValue={initialCount} />
    </div>
  )
}

データフェッチング

fetch API

// キャッシュあり(デフォルト)
async function getData() {
  const res = await fetch('https://api.example.com/data')
  return res.json()
}

// キャッシュなし
async function getData() {
  const res = await fetch('https://api.example.com/data', {
    cache: 'no-store'
  })
  return res.json()
}

// 時間ベースリバリデーション
async function getData() {
  const res = await fetch('https://api.example.com/data', {
    next: { revalidate: 3600 } // 1時間
  })
  return res.json()
}

Prisma使用例

// lib/prisma.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}

export const prisma = globalForPrisma.prisma ?? new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

// app/users/page.tsx
import { prisma } from '@/lib/prisma'

export default async function UsersPage() {
  const users = await prisma.user.findMany()

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  )
}

キャッシング戦略

リバリデーション

時間ベース(Time-based)

// 60秒ごとに再検証
fetch('https://api.example.com/data', {
  next: { revalidate: 60 }
})

オンデマンド(On-demand)

// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache'
import { NextRequest } from 'next/server'

export async function POST(request: NextRequest) {
  const path = request.nextUrl.searchParams.get('path')

  if (path) {
    revalidatePath(path)
    return Response.json({ revalidated: true, now: Date.now() })
  }

  return Response.json({ revalidated: false })
}

// 使用例
// POST /api/revalidate?path=/posts

実践例

Example 1: ブログアプリ

// app/blog/page.tsx
import Link from 'next/link'

async function getPosts() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
    next: { revalidate: 3600 }
  })
  return res.json()
}

export default async function BlogPage() {
  const posts = await getPosts()

  return (
    <div>
      <h1>Blog</h1>
      <ul>
        {posts.map((post: any) => (
          <li key={post.id}>
            <Link href={`/blog/${post.id}`}>
              {post.title}
            </Link>
          </li>
        ))}
      </ul>
    </div>
  )
}

// app/blog/[id]/page.tsx
async function getPost(id: string) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
    next: { revalidate: 3600 }
  })
  return res.json()
}

export default async function PostPage({ params }: { params: { id: string } }) {
  const post = await getPost(params.id)

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  )
}

Example 2: API Route(CRUD)

// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'

// GET /api/users
export async function GET() {
  const users = await prisma.user.findMany()
  return NextResponse.json(users)
}

// POST /api/users
export async function POST(request: NextRequest) {
  const body = await request.json()

  const user = await prisma.user.create({
    data: {
      name: body.name,
      email: body.email,
    },
  })

  return NextResponse.json(user, { status: 201 })
}

// app/api/users/[id]/route.ts
// PUT /api/users/:id
export async function PUT(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const body = await request.json()

  const user = await prisma.user.update({
    where: { id: params.id },
    data: body,
  })

  return NextResponse.json(user)
}

// DELETE /api/users/:id
export async function DELETE(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  await prisma.user.delete({
    where: { id: params.id },
  })

  return new NextResponse(null, { status: 204 })
}

Example 3: フォーム送信(Server Actions)

// app/create-post/page.tsx
import { redirect } from 'next/navigation'
import { prisma } from '@/lib/prisma'

async function createPost(formData: FormData) {
  'use server' // Server Action

  const title = formData.get('title') as string
  const content = formData.get('content') as string

  await prisma.post.create({
    data: { title, content },
  })

  redirect('/posts')
}

export default function CreatePostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Title" required />
      <textarea name="content" placeholder="Content" required />
      <button type="submit">Create</button>
    </form>
  )
}

アンチパターン

❌ 1. Client ComponentでのDB直接アクセス

'use client'
// ❌ 悪い例
import { prisma } from '@/lib/prisma'

export function UserList() {
  const users = await prisma.user.findMany() // エラー!
}
// ✅ 良い例(Server Component)
import { prisma } from '@/lib/prisma'

export default async function UserList() {
  const users = await prisma.user.findMany()
  return <ul>{/* ... */}</ul>
}

❌ 2. 不要な'use client'

// ❌ 悪い例
'use client' // 不要(インタラクティブでない)

export function UserCard({ user }: { user: User }) {
  return <div>{user.name}</div>
}
// ✅ 良い例(Server Component)
export function UserCard({ user }: { user: User }) {
  return <div>{user.name}</div>
}

Agent連携

📖 Agentへの指示例

新規ページ作成

/about ページを作成してください。
会社概要、ミッション、チーム紹介を含めてください。

API Route作成

/api/posts のCRUD APIを作成してください。
Prismaを使用して、GET, POST, PUT, DELETEをサポートしてください。

Server Actions実装

ユーザー作成フォームをServer Actionsで実装してください。
バリデーションも含めてください。

まとめ

Next.jsのベストプラクティス

  1. Server Components優先 - デフォルトで使用
  2. 適切なキャッシング - revalidateを活用
  3. 型安全性 - TypeScript + Prisma
  4. Server Actions - フォーム送信に活用

Last updated: 2025-12-26