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. 03检查 Server Actions 的验证与安全
  4. 04评估中间件、路由处理与元数据
  5. 05输出分级问题及代码示例

适用场景

  1. 01合并前审查页面、布局和路由段
  2. 02检查 Server 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 代码审查

概述

根据 Server Components、Client Components、Server Actions、缓存策略和生产就绪性标准评估 Next.js App Router 代码。按严重程度分类给出可执行的审查结果,并附上具体代码示例。将架构分析委派给 typescript-software-architect-review Agent。

适用场景

  • 合并前审查 Next.js 页面、布局和路由段
  • 验证 Server Component 与 Client Component 的边界
  • 检查 Server Actions 的安全性和正确性
  • 审查数据获取模式(fetch、缓存、重新验证)
  • 评估缓存策略(静态生成、ISR、动态渲染)
  • 评估中间件实现(身份验证、重定向、重写)
  • 审查 API 路由处理程序是否正确处理请求和响应
  • 验证 SEO 元数据配置
  • 检查 loading、error 和 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 Component 不会导入仅供客户端使用的模块。

  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. 生成审查报告:生成结构化报告,包含按严重程度分类的审查结果(严重、警告、建议)、正面观察,以及附有代码示例的优先级建议。

示例

示例 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' 边界放在组件树更深处
  • 在 Server Components 中获取数据——避免在客户端获取初始数据
  • 并行获取数据(Promise.all),避免请求瀑布
  • 为每个路由段实现完善的加载、错误和未找到状态
  • 使用 Zod 或类似库验证所有 Server Action 输入
  • 尽可能使用 revalidatePath/revalidateTag,而不是基于时间的重新验证
  • 使用 config.matcher 将中间件限制在特定路由
  • 为内容可变的动态页面实现 generateMetadata
  • 为参数已知的静态页面使用 generateStaticParams
  • 避免在 Client Components 中导入仅限服务器端的代码——使用 server-only 包

限制和警告

  • 此技能面向 Next.js App Router——Pages Router 模式可能有很大差异
  • 遵循项目使用的 Next.js 版本——某些功能仅适用于特定版本
  • 除非明确提出要求,否则不要建议从 Pages Router 迁移到 App Router
  • 开发环境和生产环境中的缓存行为不同——请在生产构建中验证
  • Server Actions 绝不能在缺少适当身份验证检查的情况下暴露敏感操作
  • 聚焦于高置信度的问题——避免将风格偏好误判为问题

参考资料

详细的审查清单和模式文档请参阅 references/ 目录:

  • references/app-router-patterns.md — App Router 最佳实践和模式
  • references/server-components.md — Server Component 与 Client Component 边界指南
  • references/performance.md — Next.js 性能优化清单

评论

支持 Markdown