nextjs-project-manager について
nextjs-project-managerは、App Routerを使ったNext.js 14+アプリの構築と保守を支援するスキルです。ルーティング、コンポーネント、データ取得、Server Actions、パフォーマンス改善のパターンを紹介します。
主な機能
- 01App Routerのルートとレイアウトのパターン
- 02Server・Client Componentの指針
- 03データ取得とServer Actions
- 04APIルートとミドルウェア
- 05ローディング、エラー、メタデータのパターン
- 06パフォーマンス最適化の指針
活用シーン
- 01ルートと共有レイアウトの作成
- 02Server Actionsによるフォーム構築
- 03Next.js固有のエラーのデバッグ
- 04アプリのパフォーマンス改善
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill nextjs-project-managerインストール後、Claude Code で/nextjs-project-managerを入力して読み込まれたか確認します。
詳細
Next.js プロジェクトマネージャースキル
概要
このスキルは、App Router を使用して本番環境に対応した Next.js 14+ アプリケーションを構築するのに役立ちます。ルーティング、コンポーネント、サーバーアクション、データ取得など、Next.js 固有のパターンを扱う際に使用してください。
基本原則
1. App Router を優先する
- すべてのルートを
src/app/ディレクトリに配置する - ルートには
page.tsx、共有レイアウトにはlayout.tsxを使用する - デフォルトではサーバーコンポーネントを使用し、必要な場合にクライアントコンポーネントを使用する
- 整理には
(group)を使ったルートグループを使用する
2. サーバーコンポーネントとクライアントコンポーネント
サーバーコンポーネント(デフォルト):
"use client"ディレクティブは不要です- async/await を直接使用できます
- データベースやバックエンドに直接アクセスできます
- クライアントに送信される JS が少なく、パフォーマンスが向上します
- フックやブラウザー API は使用できません
クライアントコンポーネント("use client"):
- 次のものが必要な場合に使用します。
- 状態(useState、useReducer)
- エフェクト(useEffect)
- イベントハンドラー(onClick、onChange)
- ブラウザー API(localStorage、window)
- フックを使用するサードパーティーライブラリ
3. データ取得のパターン
サーバーコンポーネント:
// Direct async fetch in component
export default async function Page() {
const data = await fetch('https://api.example.com/data')
const json = await data.json()
return <div>{json.title}</div>
}
クライアントコンポーネント:
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [data, setData] = useState(null)
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(setData)
}, [])
return <div>{data?.title}</div>
}
4. サーバーアクション
フォームの送信や変更には、サーバーアクションを使用します。
// app/actions.ts
'use server'
export async function createItem(formData: FormData) {
const title = formData.get('title')
// Database operation
await db.insert({ title })
revalidatePath('/items')
redirect('/items')
}
// app/form.tsx
'use client'
import { createItem } from './actions'
export function Form() {
return (
<form action={createItem}>
<input name="title" />
<button type="submit">Create</button>
</form>
)
}
よく使われるパターン
ルート構成
src/app/
├── (auth)/
│ ├── login/
│ │ └── page.tsx
│ └── signup/
│ └── page.tsx
├── (dashboard)/
│ ├── layout.tsx # Shared dashboard layout
│ ├── page.tsx # Dashboard home
│ └── settings/
│ └── page.tsx
├── api/
│ └── endpoint/
│ └── route.ts # API routes
├── layout.tsx # Root layout
└── page.tsx # Home page
レイアウト
// app/(dashboard)/layout.tsx
import { Sidebar } from '@/components/sidebar'
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="flex">
<Sidebar />
<main className="flex-1">{children}</main>
</div>
)
}
ローディング状態
// app/dashboard/loading.tsx
export default function Loading() {
return <div>Loading...</div>
}
エラー処理
// app/dashboard/error.tsx
'use client'
export default function Error({
error,
reset,
}: {
error: Error
reset: () => void
}) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
)
}
メタデータ
// app/page.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Page Title',
description: 'Page description',
}
export default function Page() {
return <div>Content</div>
}
API ルート
// app/api/items/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const items = await db.getItems()
return NextResponse.json({ items })
}
export async function POST(request: NextRequest) {
const body = await request.json()
const item = await db.createItem(body)
return NextResponse.json({ item }, { status: 201 })
}
動的ルート
// app/posts/[id]/page.tsx
export default function Post({ params }: { params: { id: string } }) {
return <div>Post {params.id}</div>
}
// Generate static params
export async function generateStaticParams() {
const posts = await getPosts()
return posts.map((post) => ({ id: post.id }))
}
ミドルウェア
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Check auth, redirect, rewrite, etc.
return NextResponse.next()
}
export const config = {
matcher: '/dashboard/:path*',
}
環境変数
// Access in Server Components or Server Actions
const apiKey = process.env.API_KEY
// Access in Client Components (must be prefixed with NEXT_PUBLIC_)
const publicKey = process.env.NEXT_PUBLIC_API_KEY
ベストプラクティスのチェックリスト
- デフォルトでサーバーコンポーネントを使用する
- 必要な場合にのみ
"use client"を追加する - 変更にはサーバーアクションを使用する
- ローディング状態には loading.tsx を実装する
- エラーバウンダリーには error.tsx を実装する
- 整理にはルートグループを使用する
- すべてのページにメタデータを追加する
- 型安全性のために TypeScript を使用する
- 適切なエラー処理を実装する
- 認証チェックにはミドルウェアを使用する
- next/image で画像を最適化する
- 大きなコンポーネントには動的インポートを使用する
デバッグのヒント
- ハイドレーションエラー:サーバーとクライアントの不一致を確認します
"use client"エラー:フックを使用するコンポーネントにディレクティブがありません- ブラウザー API にアクセスできない:クライアントコンポーネントに移動します
- データが更新されない:revalidatePath() または revalidateTag() を使用します
- ビルドエラー:適切な型指定のない非同期コンポーネントがないか確認します
パフォーマンスの最適化
- ローディング状態には React Suspense を使用する
- loading.tsx でストリーミングを実装する
- コード分割には動的インポートを使用する
- next/image で画像を最適化する
- next/font でフォントを最適化する
- ISR(Incremental Static Regeneration)を実装する
- fetch のオプションでキャッシュを使用する
このスキルを使用するタイミング
次の場合にこのスキルを呼び出してください。
- 新しいルートやページを作成するとき
- レイアウトを設定するとき
- サーバーアクションを使ったフォームを実装するとき
- Next.js 固有のエラーをデバッグするとき
- パフォーマンスを最適化するとき
- ミドルウェアを設定するとき
- API ルートを作成するとき
- メタデータを扱うとき
コメント
Markdown 対応