mcpField
N
nextjs-code-review

nextjs-code-review

github.com/giuseppe-trisciuoglioテスト・品質3653.8k 回インストール7 週間前に更新
リポジトリ

nextjs-code-review について

Next.js App Router のコードを対象に、コンポーネント境界、データ取得、キャッシュ、セキュリティ、本番対応を確認するレビュー用スキルです。重要度別の指摘に、修正例と優先順位を添えて提示します。

主な機能

  1. 01サーバー・クライアントコンポーネント境界の確認
  2. 02データ取得とキャッシュ戦略のレビュー
  3. 03Server Actions の検証とセキュリティ評価
  4. 04ミドルウェア、ルートハンドラー、メタデータの確認
  5. 05重要度別の指摘とコード例の提示

活用シーン

  1. 01マージ前のページ、レイアウト、ルートセグメントのレビュー
  2. 02Server Actions の認可と入力検証の確認
  3. 03キャッシュとオンデマンド再検証の評価
  4. 04移行や機能追加後の App Router コード確認

インストール

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

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill nextjs-code-review

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
app-router-patterns.md
performance.md
server-components.md

詳細

Next.js コードレビュー

概要

Next.js App Router のコードを、Server Components、Client Components、Server Actions、キャッシュ戦略、および本番環境への対応基準に照らして評価します。重要度別に分類した、具体的なコード例を含む実行可能な指摘を提示します。アーキテクチャ分析は typescript-software-architect-review エージェントに委任します。

使用する場面

  • マージ前に Next.js のページ、レイアウト、ルートセグメントをレビューするとき
  • Server Component と Client Component の境界を検証するとき
  • Server Actions のセキュリティと正確性を確認するとき
  • データ取得のパターン(fetch、cache、再検証)をレビューするとき
  • キャッシュ戦略(静的生成、ISR、動的レンダリング)を評価するとき
  • ミドルウェアの実装(認証、リダイレクト、リライト)を評価するとき
  • API ルートハンドラーがリクエストとレスポンスを適切に処理しているかレビューするとき
  • SEO のためにメタデータ設定を検証するとき
  • ローディング、エラー、Not Found ページの実装を確認するとき
  • Next.js の新機能を実装した後、または Pages Router から移行した後

手順

  1. 対象範囲を特定する:レビュー対象となる Next.js のルートセグメントとコンポーネントを特定します。glob を使って page.tsx、layout.tsx、loading.tsx、error.tsx、route.ts、middleware.ts ファイルを探します。

  2. コンポーネントの境界を分析する:Server Component と Client Component が適切に分離されているか確認します。'use client' が必要な箇所だけに、コンポーネントツリーのできるだけ深い位置に配置されているか確認します。Server Components がクライアント専用モジュールをインポートしていないことを確認します。

  3. データ取得をレビューする:fetch のパターンを検証します。cache と revalidate オプションが適切か、Promise.all を使ってデータを並行取得しているか、リクエストのウォーターフォールを避けているか確認します。サーバーサイドのデータ取得で機密データがクライアントに公開されていないことを確認します。

  4. キャッシュ戦略を評価する:静的レンダリングと動的レンダリングの判断をレビューします。静的生成での generateStaticParams の使用、オンデマンド再検証のための revalidatePath/revalidateTag、API ルートに適切なキャッシュヘッダーが設定されているか確認します。

  5. Server Actions を評価する:フォームアクションのバリデーション(クライアント側とサーバー側の両方)、エラー処理、useOptimistic による楽観的更新、セキュリティ(アクションが認可なしに機密性の高い操作を公開していないこと)をレビューします。

  6. ミドルウェアを確認する:リクエストのマッチング、認証/認可ロジック、レスポンスの変更、パフォーマンスへの影響についてミドルウェアをレビューします。必要なルートでのみ実行されることを確認します。

  7. メタデータと SEO をレビューする:generateMetadata 関数、Open Graph タグ、構造化データ、robots.txt、sitemap.xml の設定を確認します。コンテンツが変動するページで、動的メタデータが適切に実装されていることを確認します。

  8. 指摘事項を検証する:最終化する前に、実際のコードを確認して各問題を検証します。パターン違反が存在することを確認し、提案する修正がコードベースに適用できることを確かめ、誤検知を除外します。

  9. レビュー報告書を作成する:重要度(Critical、Warning、Suggestion)別の指摘事項、良い点、コード例を含む優先順位付きの推奨事項をまとめた構造化レポートを作成します。

例

例 1:Server/Client Component の境界
// ❌ Bad: Entire page marked as client when only a button needs interactivity
'use client';

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await fetch(`/api/products/${params.id}`);
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <button onClick={() => addToCart(product.id)}>Add to Cart</button>
    </div>
  );
}

// ✅ Good: Server Component with isolated Client Component
// app/products/[id]/page.tsx (Server Component)
import { AddToCartButton } from './add-to-cart-button';

export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const product = await getProduct(id);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <AddToCartButton productId={product.id} />
    </div>
  );
}

// app/products/[id]/add-to-cart-button.tsx (Client Component)
'use client';

export function AddToCartButton({ productId }: { productId: string }) {
  return <button onClick={() => addToCart(productId)}>Add to Cart</button>;
}
例 2:データ取得のパターン
// ❌ Bad: Sequential data fetching creates waterfall
export default async function DashboardPage() {
  const user = await getUser();
  const orders = await getOrders(user.id);
  const analytics = await getAnalytics(user.id);
  return <Dashboard user={user} orders={orders} analytics={analytics} />;
}

// ✅ Good: Parallel data fetching with proper Suspense boundaries
export default async function DashboardPage() {
  const user = await getUser();
  const [orders, analytics] = await Promise.all([
    getOrders(user.id),
    getAnalytics(user.id),
  ]);
  return <Dashboard user={user} orders={orders} analytics={analytics} />;
}

// ✅ Even better: Streaming with Suspense for independent sections
export default async function DashboardPage() {
  const user = await getUser();
  return (
    <div>
      <UserHeader user={user} />
      <Suspense fallback={<OrdersSkeleton />}>
        <OrdersSection userId={user.id} />
      </Suspense>
      <Suspense fallback={<AnalyticsSkeleton />}>
        <AnalyticsSection userId={user.id} />
      </Suspense>
    </div>
  );
}
例 3:Server Actions のセキュリティ
// ❌ Bad: Server Action without validation or authorization
'use server';

export async function deleteUser(id: string) {
  await db.user.delete({ where: { id } });
}

// ✅ Good: Server Action with validation, authorization, and error handling
'use server';

import { z } from 'zod';
import { auth } from '@/lib/auth';
import { revalidatePath } from 'next/cache';

const deleteUserSchema = z.object({ id: z.string().uuid() });

export async function deleteUser(rawData: { id: string }) {
  const session = await auth();
  if (!session || session.user.role !== 'admin') {
    throw new Error('Unauthorized');
  }

  const { id } = deleteUserSchema.parse(rawData);
  await db.user.delete({ where: { id } });
  revalidatePath('/admin/users');
}
例 4:キャッシュと再検証
// ❌ Bad: No cache control, fetches on every request
export default async function BlogPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return <PostList posts={posts} />;
}

// ✅ Good: Explicit caching with time-based revalidation
export default async function BlogPage() {
  const posts = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600, tags: ['blog-posts'] },
  }).then(r => r.json());
  return <PostList posts={posts} />;
}

// Revalidation in Server Action
'use server';
export async function publishPost(data: FormData) {
  await db.post.create({ data: parseFormData(data) });
  revalidateTag('blog-posts');
}
例 5:ミドルウェアのレビュー
// ❌ Bad: Middleware runs on all routes including static assets
import { NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const session = request.cookies.get('session');
  if (!session) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
}
// Missing config.matcher

// ✅ Good: Scoped middleware with proper matcher
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const session = request.cookies.get('session');
  if (!session) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/protected/:path*'],
};

レビュー出力形式

すべてのコードレビューの指摘事項を、次の形式でまとめます。

1. 概要

全体的な品質スコア(1~10)と主な所見を含む簡潔な概要。

2. 重大な問題(必ず修正)

セキュリティ上の脆弱性、データの露出、または機能の破損につながる問題。

3. 警告(修正を推奨)

ベストプラクティスに違反する、パフォーマンス上の問題を引き起こす、または保守性を低下させる問題。

4. 提案(改善を検討)

コードの整理、パフォーマンス、または開発者体験の改善。

5. 肯定的な所見

適切に実装されたパターンや、評価すべき優れたプラクティスです。

6. 推奨事項

影響の大きい改善について、コード例を添えた優先度順の次のステップです。

ベストプラクティス

  • 'use client' の境界は、可能な限りツリーの深い位置に配置します
  • サーバーコンポーネントでデータを取得し、初期データのクライアント側での取得は避けます
  • 並列でデータを取得し(Promise.all)、リクエストのウォーターフォールを防ぎます
  • すべてのルートセグメントに、適切な読み込み状態、エラー状態、未検出状態を実装します
  • すべてのサーバーアクションの入力を、Zod などのライブラリで検証します
  • 可能な場合は、時間ベースの再検証ではなく revalidatePath/revalidateTag を使用します
  • config.matcher を使用して、ミドルウェアの適用対象を特定のルートに絞ります
  • コンテンツが変動する動的ページには generateMetadata を実装します
  • パラメーターが既知の静的ページには generateStaticParams を使用します
  • クライアントコンポーネントでサーバー専用コードをインポートせず、server-only パッケージを使用します

制約と警告

  • このスキルは Next.js App Router を対象としています。Pages Router のパターンは大きく異なる場合があります
  • プロジェクトの Next.js のバージョンに従います。一部の機能はバージョン固有です
  • 明示的に依頼されない限り、Pages Router から App Router への移行を提案しないでください
  • キャッシュの動作は開発環境と本番環境で異なるため、本番ビルドで検証してください
  • サーバーアクションで機密性の高い操作を公開する場合は、適切な認証チェックを必ず実装してください
  • 確度の高い問題に焦点を当て、スタイルの好みに関する誤検知を避けてください

参考資料

詳細なレビュー用チェックリストとパターンのドキュメントについては、references/ ディレクトリを参照してください。

  • references/app-router-patterns.md — App Router のベストプラクティスとパターン
  • references/server-components.md — サーバーコンポーネントとクライアントコンポーネントの境界に関するガイド
  • references/performance.md — Next.js のパフォーマンス最適化チェックリスト

コメント