mcpField
N
nextjs-project-manager

nextjs-project-manager

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

nextjs-project-manager について

nextjs-project-managerは、App Routerを使ったNext.js 14+アプリの構築と保守を支援するスキルです。ルーティング、コンポーネント、データ取得、Server Actions、パフォーマンス改善のパターンを紹介します。

主な機能

  1. 01App Routerのルートとレイアウトのパターン
  2. 02Server・Client Componentの指針
  3. 03データ取得とServer Actions
  4. 04APIルートとミドルウェア
  5. 05ローディング、エラー、メタデータのパターン
  6. 06パフォーマンス最適化の指針

活用シーン

  1. 01ルートと共有レイアウトの作成
  2. 02Server Actionsによるフォーム構築
  3. 03Next.js固有のエラーのデバッグ
  4. 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 で画像を最適化する
  • 大きなコンポーネントには動的インポートを使用する

デバッグのヒント

  1. ハイドレーションエラー:サーバーとクライアントの不一致を確認します
  2. "use client" エラー:フックを使用するコンポーネントにディレクティブがありません
  3. ブラウザー API にアクセスできない:クライアントコンポーネントに移動します
  4. データが更新されない:revalidatePath() または revalidateTag() を使用します
  5. ビルドエラー:適切な型指定のない非同期コンポーネントがないか確認します

パフォーマンスの最適化

  • ローディング状態には React Suspense を使用する
  • loading.tsx でストリーミングを実装する
  • コード分割には動的インポートを使用する
  • next/image で画像を最適化する
  • next/font でフォントを最適化する
  • ISR(Incremental Static Regeneration)を実装する
  • fetch のオプションでキャッシュを使用する

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

次の場合にこのスキルを呼び出してください。

  • 新しいルートやページを作成するとき
  • レイアウトを設定するとき
  • サーバーアクションを使ったフォームを実装するとき
  • Next.js 固有のエラーをデバッグするとき
  • パフォーマンスを最適化するとき
  • ミドルウェアを設定するとき
  • API ルートを作成するとき
  • メタデータを扱うとき

コメント