mcpField
N
nextjs

nextjs

github.com/jackspace开发1659 次安装13 周前更新
代码仓库

关于 nextjs

nextjs 技能为使用 Next.js 16 App Router 的开发者提供生产实践参考,涵盖路由、缓存、服务端组件及迁移变化。内容也涉及 React 19.2、性能优化和常见错误。

主要功能

  1. 01App Router 路由与布局模式
  2. 02Server Components 和 Server Actions
  3. 03缓存组件与缓存 API
  4. 04Next.js 15 到 16 的迁移指导
  5. 05元数据、图片与字体优化
  6. 06常见错误与模板参考

适用场景

  1. 01构建 Next.js 16 App Router 页面
  2. 02实现服务端数据获取与表单操作
  3. 03配置缓存和部分预渲染
  4. 04将 Next.js 15 项目迁移到 16

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill nextjs

安装后在 Claude Code 中输入/nextjs确认已加载。

附带文件README.mdSKILL.json

详细介绍

Next.js App Router - 生产环境模式

版本:Next.js 16.0.0 React 版本:19.2.0 Node.js:20.9+ 上次验证时间:2025-10-24


目录

  1. 何时使用此技能
  2. 何时不使用此技能
  3. Next.js 16 重大变更
  4. 缓存组件与缓存 API
  5. 服务端组件
  6. 服务端操作
  7. 路由处理程序
  8. Proxy 与 Middleware
  9. 并行路由与路由组
  10. React 19.2 功能
  11. 元数据 API
  12. 图像与字体优化
  13. 性能模式
  14. TypeScript 配置
  15. 常见错误与解决方案
  16. 模板参考
  17. 其他资源

何时使用此技能

在以下情况下使用此技能:

  • Next.js 16 App Router 模式(布局、加载、错误边界、路由)
  • 服务端组件最佳实践(数据获取、组合、流式传输)
  • 服务端操作模式(表单、变更、重新验证、错误处理)
  • 使用 "use cache" 指令的缓存组件(Next.js 16 新增)
  • 全新缓存 API:revalidateTag()、updateTag()、refresh()(Next.js 16 中已更新)
  • 从 Next.js 15 迁移到 16(异步 params、proxy.ts、并行路由)
  • 路由处理程序(API 端点、webhook、流式响应)
  • Proxy 模式(Next.js 16 中 proxy.ts 替代 middleware.ts)
  • 异步路由参数(params、searchParams、cookies()、headers() 现在均为异步)
  • 带 default.js 的并行路由(Next.js 16 中的重大变更)
  • React 19.2 功能(View Transitions、useEffectEvent()、React Compiler)
  • 元数据 API(SEO、Open Graph、Twitter Cards、站点地图)
  • 图像优化(Next.js 16 中默认设置已更新的 next/image)
  • 字体优化(next/font 模式)
  • Turbopack 配置(在 Next.js 16 中已稳定并设为默认)
  • 性能优化(延迟加载、代码拆分、PPR、ISR)
  • TypeScript 配置(严格模式、路径别名)

何时不使用此技能

以下情况请勿使用此技能:

  • 部署到 Cloudflare Workers → 请改用 cloudflare-nextjs 技能
  • Pages Router 模式 → 此技能仅涵盖 App Router(Pages Router 已过时)
  • 身份验证库 → 请使用 clerk-auth、auth-js 或其他专门用于身份验证的技能
  • 数据库集成 → 请使用 cloudflare-d1、drizzle-orm-d1 或其他数据库专用技能
  • UI 组件库 → Tailwind + shadcn/ui 请使用 tailwind-v4-shadcn 技能
  • 状态管理 → 请使用 zustand-state-management、tanstack-query 技能
  • 表单库 → 请使用 react-hook-form-zod 技能
  • Vercel 专属功能 → 请参阅 Vercel 平台文档
  • Next.js Enterprise 功能(ISR、DPR)→ 请参阅 Next.js Enterprise 文档
  • 部署配置 → 请使用平台专用部署技能

与其他技能的关系:

  • cloudflare-nextjs:用于将 Next.js 部署到 Cloudflare Workers(如果要部署到 Cloudflare,请同时使用这两种技能)
  • tailwind-v4-shadcn:用于配置 Tailwind v4 + shadcn/ui(可与此技能组合使用)
  • clerk-auth:用于在 Next.js 中使用 Clerk 进行身份验证(可与此技能组合使用)
  • auth-js:用于集成 Auth.js(NextAuth)(可与此技能组合使用)

Next.js 16 重大变更

重要:Next.js 16 引入了多项重大变更。如果要从 Next.js 15 或更早版本迁移,请仔细阅读本节。

1. 异步路由参数(重大变更)

重大变更:params、searchParams、cookies()、headers()、draftMode() 现在都是异步的,必须使用 await。

之前(Next.js 15):

// ❌ This no longer works in Next.js 16
export default function Page({ params, searchParams }: {
  params: { slug: string }
  searchParams: { query: string }
}) {
  const slug = params.slug // ❌ Error: params is a Promise
  const query = searchParams.query // ❌ Error: searchParams is a Promise
  return <div>{slug}</div>
}

之后(Next.js 16):

// ✅ Correct: await params and searchParams
export default async function Page({ params, searchParams }: {
  params: Promise<{ slug: string }>
  searchParams: Promise<{ query: string }>
}) {
  const { slug } = await params // ✅ Await the promise
  const { query } = await searchParams // ✅ Await the promise
  return <div>{slug}</div>
}

适用范围:

  • 页面、布局、路由处理程序中的 params
  • 页面中的 searchParams
  • 来自 next/headers 的 cookies()
  • 来自 next/headers 的 headers()
  • 来自 next/headers 的 draftMode()

迁移:

// ❌ Before
import { cookies, headers } from 'next/headers'

export function MyComponent() {
  const cookieStore = cookies() // ❌ Sync access
  const headersList = headers() // ❌ Sync access
}

// ✅ After
import { cookies, headers } from 'next/headers'

export async function MyComponent() {
  const cookieStore = await cookies() // ✅ Async access
  const headersList = await headers() // ✅ Async access
}

Codemod:运行 npx @next/codemod@canary upgrade latest 自动迁移。

参见模板:templates/app-router-async-params.tsx


2. Middleware → Proxy 迁移(重大变更)

重大变更:middleware.ts 在 Next.js 16 中已弃用。请改用 proxy.ts。

变更原因:proxy.ts 通过在 Node.js 运行时(而非 Edge 运行时)运行,明确了网络边界。这能更清晰地区分边缘中间件和服务端代理。

迁移步骤:

  1. 重命名文件:middleware.ts → proxy.ts
  2. 重命名函数:middleware → proxy
  3. 更新配置:matcher → config.matcher(语法相同)

之前(Next.js 15):

// middleware.ts ❌ Deprecated in Next.js 16
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  response.headers.set('x-custom-header', 'value')
  return response
}

export const config = {
  matcher: '/api/:path*',
}

之后(Next.js 16):

// proxy.ts ✅ New in Next.js 16
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function proxy(request: NextRequest) {
  const response = NextResponse.next()
  response.headers.set('x-custom-header', 'value')
  return response
}

export const config = {
  matcher: '/api/:path*',
}

注意:middleware.ts 在 Next.js 16 中仍可使用,但已弃用。请迁移到 proxy.ts,以确保未来兼容性。

参见模板:templates/proxy-migration.ts 参见参考文档:references/proxy-vs-middleware.md


3. 并行路由需要 default.js(重大变更)

重大变更:并行路由现在必须显式提供 default.js 文件。没有这些文件,软导航时路由将失败。

结构:

app/
├── @auth/
│   ├── login/
│   │   └── page.tsx
│   └── default.tsx    ← REQUIRED in Next.js 16
├── @dashboard/
│   ├── overview/
│   │   └── page.tsx
│   └── default.tsx    ← REQUIRED in Next.js 16
└── layout.tsx

布局:

// app/layout.tsx
export default function Layout({
  children,
  auth,
  dashboard,
}: {
  children: React.ReactNode
  auth: React.ReactNode
  dashboard: React.ReactNode
}) {
  return (
    <html>
      <body>
        {auth}
        {dashboard}
        {children}
      </body>
    </html>
  )
}

默认回退(必需):

// app/@auth/default.tsx
export default function AuthDefault() {
  return null // or <Skeleton /> or redirect
}

// app/@dashboard/default.tsx
export default function DashboardDefault() {
  return null
}

必需原因:Next.js 16 更改了并行路由处理软导航的方式。没有 default.js,客户端导航时未匹配的插槽会报错。

参见模板:templates/parallel-routes-with-default.tsx


4. 移除的功能(重大变更)

以下功能在 Next.js 16 中已移除:

  1. AMP 支持 - 已完全移除。请迁移到标准页面。
  2. next lint 命令 - 请直接使用 ESLint 或 Biome。
  3. serverRuntimeConfig 和 publicRuntimeConfig - 请改用环境变量。
  4. experimental.ppr 标志 - 已演进为 Cache Components。请使用 "use cache" 指令。
  5. 自动应用 scroll-behavior: smooth - 如有需要,请手动添加。
  6. Node.js 18 支持 - 最低版本现在为 20.9+。

迁移:

  • AMP:将 AMP 页面转换为标准页面,或使用独立的 AMP 实现。
  • 代码检查:直接运行 npx eslint . 或 npx biome lint .。
  • 配置:将 serverRuntimeConfig 替换为 process.env.VARIABLE。
  • PPR:将 experimental.ppr 迁移为 "use cache" 指令(参见 Cache Components 部分)。

5. 版本要求(重大变更)

Next.js 16 要求:

  • Node.js:20.9+(不再支持 Node.js 18)
  • TypeScript:5.1+(如果使用 TypeScript)
  • React:19.2+(随 Next.js 16 自动安装)
  • 浏览器:Chrome 111+、Safari 16.4+、Firefox 109+、Edge 111+

检查版本:

node --version    # Should be 20.9+
npm --version     # Should be 10+
npx next --version # Should be 16.0.0+

升级 Node.js:

# Using nvm
nvm install 20
nvm use 20
nvm alias default 20

# Using Homebrew (macOS)
brew install node@20

# Using apt (Ubuntu/Debian)
sudo apt update
sudo apt install nodejs npm

6. 图像默认值已更改(重大变更)

Next.js 16 更改了 next/image 的默认值:

设置Next.js 15Next.js 16
TTL(缓存时长)60 秒4 小时
imageSizes[16, 32, 48, 64, 96, 128, 256, 384][640, 750, 828, 1080, 1200](减少)
qualities[75, 90, 100][75](单一质量)

影响:

  • 图像缓存时间更长(4 小时,而非 60 秒)
  • 生成的图像尺寸更少(构建体积更小,但尺寸粒度更粗)
  • 仅生成单一质量(75),而非多个质量

覆盖默认值(如有需要):

// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    minimumCacheTTL: 60, // Revert to 60 seconds
    deviceSizes: [640, 750, 828, 1080, 1200, 1920], // Add larger sizes
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // Restore old sizes
    formats: ['image/webp'], // Default
  },
}

export default config

参见模板:templates/image-optimization.tsx


缓存组件与缓存 API

Next.js 16 新增:缓存组件通过 "use cache" 指令引入选择性启用缓存,取代 Next.js 15 中的隐式缓存。

1. 概览

变更内容:

  • Next.js 15:隐式缓存(默认缓存所有服务器组件)
  • Next.js 16:通过 "use cache" 指令选择性启用缓存

变更原因:显式缓存让开发者拥有更多控制权,并使缓存行为可预测。

缓存组件支持:

  • 组件级缓存(缓存特定组件,而非整个页面)
  • 函数级缓存(缓存开销较大的计算)
  • 页面级缓存(有选择地缓存整个页面)
  • 部分预渲染(PPR)——缓存静态部分,按需渲染动态部分

2. "use cache" 指令

语法:在服务器组件、函数或路由处理程序的顶部添加 "use cache"。

组件级缓存:

// app/components/expensive-component.tsx
'use cache'

export async function ExpensiveComponent() {
  const data = await fetch('https://api.example.com/data')
  const json = await data.json()

  return (
    <div>
      <h1>{json.title}</h1>
      <p>{json.description}</p>
    </div>
  )
}

函数级缓存:

// lib/data.ts
'use cache'

export async function getExpensiveData(id: string) {
  const response = await fetch(`https://api.example.com/items/${id}`)
  return response.json()
}

// Usage in component
import { getExpensiveData } from '@/lib/data'

export async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const product = await getExpensiveData(id) // Cached

  return <div>{product.name}</div>
}

页面级缓存:

// app/blog/[slug]/page.tsx
'use cache'

export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json())
  return posts.map((post: { slug: string }) => ({ slug: post.slug }))
}

export default async function BlogPost({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const post = await fetch(`https://api.example.com/posts/${slug}`).then(r => r.json())

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

参见模板:templates/cache-component-use-cache.tsx


3. 部分预渲染(PPR)

PPR 支持缓存页面的静态部分,同时按需渲染动态部分。

模式:

// app/dashboard/page.tsx

// Static header (cached)
'use cache'
async function StaticHeader() {
  return <header>My App</header>
}

// Dynamic user info (not cached)
async function DynamicUserInfo() {
  const cookieStore = await cookies()
  const userId = cookieStore.get('userId')?.value
  const user = await fetch(`/api/users/${userId}`).then(r => r.json())

  return <div>Welcome, {user.name}</div>
}

// Page combines both
export default function Dashboard() {
  return (
    <div>
      <StaticHeader /> {/* Cached */}
      <DynamicUserInfo /> {/* Dynamic */}
    </div>
  )
}

适用场景:

  • 页面同时包含静态内容和动态内容
  • 希望缓存布局、页眉和页脚,同时渲染针对用户的个性化内容
  • 需要快速初始加载(静态部分)和个性化内容(动态部分)

参见参考资料:references/cache-components-guide.md


4. revalidateTag()——更新后的 API

重大变更:revalidateTag() 现在需要第二个参数(cacheLife 配置),以实现 stale-while-revalidate 行为。

之前(Next.js 15):

import { revalidateTag } from 'next/cache'

export async function updatePost(id: string) {
  await fetch(`/api/posts/${id}`, { method: 'PATCH' })
  revalidateTag('posts') // ❌ Only one argument in Next.js 15
}

之后(Next.js 16):

import { revalidateTag } from 'next/cache'

export async function updatePost(id: string) {
  await fetch(`/api/posts/${id}`, { method: 'PATCH' })
  revalidateTag('posts', 'max') // ✅ Second argument required in Next.js 16
}

内置缓存生命周期配置:

  • 'max'——最大过期时间(大多数场景推荐使用)
  • 'hours'——数小时后过期
  • 'days'——数天后过期
  • 'weeks'——数周后过期
  • 'default'——默认缓存行为

自定义缓存生命周期配置:

revalidateTag('posts', {
  stale: 3600, // Stale after 1 hour (seconds)
  revalidate: 86400, // Revalidate every 24 hours (seconds)
  expire: false, // Never expire (optional)
})

服务器操作中的模式:

'use server'

import { revalidateTag } from 'next/cache'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  await fetch('/api/posts', {
    method: 'POST',
    body: JSON.stringify({ title, content }),
  })

  revalidateTag('posts', 'max') // ✅ Revalidate with max staleness
}

参见模板:templates/revalidate-tag-cache-life.ts


5. updateTag()——新增 API(仅限服务器操作)

Next.js 16 新增:updateTag() 为服务器操作提供读己之写语义。

功能:

  • 立即使缓存过期
  • 在同一个请求中刷新数据
  • 在变更后立即显示更新的数据(无陈旧数据)

与 revalidateTag() 的区别:

  • revalidateTag():stale-while-revalidate(显示陈旧数据,并在后台重新验证)
  • updateTag():立即刷新(使缓存过期,并在同一个请求中获取最新数据)

适用场景:表单、用户设置,或任何用户期望立即得到反馈的变更操作。

模式:

'use server'

import { updateTag } from 'next/cache'

export async function updateUserProfile(formData: FormData) {
  const name = formData.get('name') as string
  const email = formData.get('email') as string

  // Update database
  await db.users.update({ name, email })

  // Immediately refresh cache (read-your-writes)
  updateTag('user-profile')

  // User sees updated data immediately (no stale data)
}

适用场景:

  • updateTag():用户设置、个人资料更新、关键变更操作(立即反馈)
  • revalidateTag():博客文章、产品列表、非关键更新(后台重新验证)

参见模板:templates/server-action-update-tag.ts


6. refresh()——新增 API(仅限服务器操作)

Next.js 16 新增:refresh() 仅刷新未缓存的数据(与客户端的 router.refresh() 互为补充)。

适用场景:

  • 刷新动态数据,同时不影响缓存数据
  • 在服务器端配合 router.refresh() 使用

模式:

'use server'

import { refresh } from 'next/cache'

export async function refreshDashboard() {
  // Refresh uncached data (e.g., real-time metrics)
  refresh()

  // Cached data (e.g., static header) remains cached
}

与 revalidateTag() 和 updateTag() 的区别:

  • refresh():仅刷新未缓存的数据
  • revalidateTag():重新验证带有特定标签的数据(stale-while-revalidate)
  • updateTag():立即使带有特定标签的数据过期并刷新

参见参考资料:references/cache-components-guide.md


服务器组件

服务器组件是在服务器上渲染的 React 组件。它们支持高效的数据获取、缩小客户端包体积并提升性能。

1. 服务端组件基础

默认行为:除非标记为 'use client',否则 App Router 中的所有组件默认都是服务端组件。

示例:

// app/posts/page.tsx (Server Component by default)
export default async function PostsPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json())

  return (
    <div>
      {posts.map((post: { id: string; title: string }) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  )
}

规则:

  • ✅ 可以直接在组件主体中 await Promise
  • ✅ 可以访问 cookies()、headers()、draftMode()(需使用 await)
  • ✅ 可以使用 Node.js API(fs、path 等)
  • ❌ 不能使用浏览器 API(window、document、localStorage)
  • ❌ 不能使用 React Hook(useState、useEffect 等)
  • ❌ 不能使用事件处理器(onClick、onChange 等)

2. 在服务端组件中获取数据

模式:直接在组件主体中使用 async/await。

// app/products/[id]/page.tsx
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params

  // Fetch data directly in component
  const product = await fetch(`https://api.example.com/products/${id}`)
    .then(r => r.json())

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>
    </div>
  )
}

并行获取数据:

export default async function Dashboard() {
  // Fetch in parallel with Promise.all
  const [user, posts, comments] = await Promise.all([
    fetch('/api/user').then(r => r.json()),
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/comments').then(r => r.json()),
  ])

  return (
    <div>
      <UserInfo user={user} />
      <PostsList posts={posts} />
      <CommentsList comments={comments} />
    </div>
  )
}

顺序获取数据(需要时):

export default async function UserPosts({ params }: { params: Promise<{ userId: string }> }) {
  const { userId } = await params

  // Fetch user first
  const user = await fetch(`/api/users/${userId}`).then(r => r.json())

  // Then fetch user's posts (depends on user data)
  const posts = await fetch(`/api/posts?userId=${user.id}`).then(r => r.json())

  return (
    <div>
      <h1>{user.name}'s Posts</h1>
      <ul>
        {posts.map((post: { id: string; title: string }) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

参见模板:templates/server-component-streaming.tsx


3. 使用 Suspense 进行流式传输

模式:将耗时组件包裹在 <Suspense> 中,以便在内容加载时进行流式传输。

import { Suspense } from 'react'

// Fast component (loads immediately)
async function Header() {
  return <header>My App</header>
}

// Slow component (takes 2 seconds)
async function SlowData() {
  await new Promise(resolve => setTimeout(resolve, 2000))
  const data = await fetch('/api/slow-data').then(r => r.json())
  return <div>{data.content}</div>
}

// Page streams content
export default function Page() {
  return (
    <div>
      <Header /> {/* Loads immediately */}

      <Suspense fallback={<div>Loading...</div>}>
        <SlowData /> {/* Streams when ready */}
      </Suspense>
    </div>
  )
}

适用场景:

  • 页面包含耗时的 API 调用
  • 希望立即显示 UI(无需等待所有数据)
  • 提升感知性能

参见参考资料:references/server-components-patterns.md


4. 服务端组件与客户端组件

适用服务端组件的场景(默认):

  • 从 API/数据库获取数据
  • 访问后端资源(文件、环境变量)
  • 将大型依赖保留在服务端(减小打包体积)
  • 渲染静态内容

适用客户端组件的场景('use client'):

  • 需要使用 React Hook(useState、useEffect、useContext)
  • 需要使用事件处理器(onClick、onChange、onSubmit)
  • 需要使用浏览器 API(window、localStorage、navigator)
  • 需要使用依赖浏览器 API 的第三方库(图表、地图等)

模式:默认使用服务端组件,仅在需要时添加 'use client'。

// app/components/interactive-button.tsx
'use client' // Client Component

import { useState } from 'react'

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

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  )
}

// app/page.tsx (Server Component)
import { InteractiveButton } from './components/interactive-button'

export default async function Page() {
  const data = await fetch('/api/data').then(r => r.json())

  return (
    <div>
      <h1>{data.title}</h1>
      <InteractiveButton /> {/* Client Component inside Server Component */}
    </div>
  )
}

组合规则:

  • ✅ 服务端组件可以导入客户端组件
  • ✅ 客户端组件可以导入客户端组件
  • ✅ 客户端组件可以通过 props 将服务端组件作为子组件渲染
  • ❌ 客户端组件不能直接导入服务端组件

参见参考资料:references/server-components-patterns.md


服务端操作

服务端操作是在服务端运行的异步函数。它们支持服务端变更、表单处理和数据重新验证。

1. 服务端操作基础

定义:添加 'use server' 指令以创建服务端操作。

文件级服务端操作:

// app/actions.ts
'use server'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  // Mutate database
  await db.posts.create({ title, content })

  // Revalidate cache
  revalidateTag('posts', 'max')
}

内联服务端操作:

// app/posts/new/page.tsx
export default function NewPostPage() {
  async function createPost(formData: FormData) {
    'use server'

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

    await db.posts.create({ title, content })
    revalidateTag('posts', 'max')
  }

  return (
    <form action={createPost}>
      <input name="title" />
      <textarea name="content" />
      <button type="submit">Create Post</button>
    </form>
  )
}

参见模板:templates/server-actions-form.tsx


2. 表单处理

基本表单:

// app/components/create-post-form.tsx
import { createPost } from '@/app/actions'

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <label>
        Title:
        <input type="text" name="title" required />
      </label>

      <label>
        Content:
        <textarea name="content" required />
      </label>

      <button type="submit">Create Post</button>
    </form>
  )
}

包含加载状态(useFormStatus):

'use client'

import { useFormStatus } from 'react-dom'
import { createPost } from '@/app/actions'

function SubmitButton() {
  const { pending } = useFormStatus()

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Creating...' : 'Create Post'}
    </button>
  )
}

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <input type="text" name="title" required />
      <textarea name="content" required />
      <SubmitButton />
    </form>
  )
}

包含验证:

// app/actions.ts
'use server'

import { z } from 'zod'
import { redirect } from 'next/navigation'

const PostSchema = z.object({
  title: z.string().min(3, 'Title must be at least 3 characters'),
  content: z.string().min(10, 'Content must be at least 10 characters'),
})

export async function createPost(formData: FormData) {
  const rawData = {
    title: formData.get('title'),
    content: formData.get('content'),
  }

  // Validate
  const parsed = PostSchema.safeParse(rawData)

  if (!parsed.success) {
    return {
      errors: parsed.error.flatten().fieldErrors,
    }
  }

  // Mutate
  await db.posts.create(parsed.data)

  // Revalidate and redirect
  revalidateTag('posts', 'max')
  redirect('/posts')
}

参见模板:templates/server-actions-form.tsx 参见参考资料:references/server-actions-guide.md


3. 错误处理

模式:从服务端操作返回错误对象,并在客户端组件中处理。

服务端操作:

// app/actions.ts
'use server'

export async function deletePost(id: string) {
  try {
    await db.posts.delete({ where: { id } })
    revalidateTag('posts', 'max')
    return { success: true }
  } catch (error) {
    return {
      success: false,
      error: 'Failed to delete post. Please try again.'
    }
  }
}

客户端组件:

'use client'

import { useState } from 'react'
import { deletePost } from '@/app/actions'

export function DeleteButton({ postId }: { postId: string }) {
  const [error, setError] = useState<string | null>(null)

  async function handleDelete() {
    const result = await deletePost(postId)

    if (!result.success) {
      setError(result.error)
    }
  }

  return (
    <div>
      <button onClick={handleDelete}>Delete Post</button>
      {error && <p className="error">{error}</p>}
    </div>
  )
}

4. 乐观更新

模式:立即显示 UI 更新,然后与服务端同步。

'use client'

import { useOptimistic } from 'react'
import { likePost } from '@/app/actions'

export function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    initialLikes,
    (state, amount: number) => state + amount
  )

  async function handleLike() {
    // Update UI immediately
    addOptimisticLike(1)

    // Sync with server
    await likePost(postId)
  }

  return (
    <button onClick={handleLike}>
      ❤️ {optimisticLikes} likes
    </button>
  )
}

参见参考资料:references/server-actions-guide.md


路由处理器

路由处理器是 App Router 中的服务端 API 端点。它们取代了 Pages Router 中的 API Routes。

1. 基本路由处理器

文件:app/api/hello/route.ts

import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json({ message: 'Hello, World!' })
}

export async function POST(request: Request) {
  const body = await request.json()

  return NextResponse.json({
    message: 'Post created',
    data: body
  })
}

支持的方法:GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS

参见模板:templates/route-handler-api.ts


2. 动态路由

文件:app/api/posts/[id]/route.ts

import { NextResponse } from 'next/server'

export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params // ✅ Await params in Next.js 16

  const post = await db.posts.findUnique({ where: { id } })

  if (!post) {
    return NextResponse.json(
      { error: 'Post not found' },
      { status: 404 }
    )
  }

  return NextResponse.json(post)
}

export async function DELETE(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params

  await db.posts.delete({ where: { id } })

  return NextResponse.json({ message: 'Post deleted' })
}

3. 搜索参数

URL:/api/posts?tag=javascript&limit=10

import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const tag = searchParams.get('tag')
  const limit = parseInt(searchParams.get('limit') || '10')

  const posts = await db.posts.findMany({
    where: { tags: { has: tag } },
    take: limit,
  })

  return NextResponse.json(posts)
}

4. Webhook

模式:处理来自第三方服务的传入 Webhook。

// app/api/webhooks/stripe/route.ts
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'

export async function POST(request: Request) {
  const body = await request.text()
  const headersList = await headers() // ✅ Await headers in Next.js 16
  const signature = headersList.get('stripe-signature')

  // Verify webhook signature
  const event = stripe.webhooks.constructEvent(
    body,
    signature!,
    process.env.STRIPE_WEBHOOK_SECRET!
  )

  // Handle event
  switch (event.type) {
    case 'payment_intent.succeeded':
      await handlePaymentSuccess(event.data.object)
      break
    case 'payment_intent.failed':
      await handlePaymentFailure(event.data.object)
      break
  }

  return NextResponse.json({ received: true })
}

参见模板:templates/route-handler-api.ts 参见参考资料:references/route-handlers-reference.md


Proxy 与 Middleware

Next.js 16 引入了 proxy.ts,用于替代 middleware.ts。

为什么要变更?
  • middleware.ts:在 Edge 运行时运行(Node.js API 受限)
  • proxy.ts:在 Node.js 运行时运行(支持完整的 Node.js API)

新的 proxy.ts 明确了网络边界,并提供更大的灵活性。

迁移

之前(middleware.ts):

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Check auth
  const token = request.cookies.get('token')

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}

之后(proxy.ts):

// proxy.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function proxy(request: NextRequest) {
  // Check auth
  const token = request.cookies.get('token')

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}

参见模板:templates/proxy-migration.ts 参见参考:references/proxy-vs-middleware.md


并行路由与路由组

1. 并行路由

使用场景:在同一布局中渲染多个页面(例如,模态框 + 主内容、仪表板面板)。

结构:

app/
├── @modal/
│   ├── login/
│   │   └── page.tsx
│   └── default.tsx  ← REQUIRED in Next.js 16
├── @feed/
│   ├── trending/
│   │   └── page.tsx
│   └── default.tsx  ← REQUIRED in Next.js 16
└── layout.tsx

布局:

// app/layout.tsx
export default function Layout({
  children,
  modal,
  feed,
}: {
  children: React.ReactNode
  modal: React.ReactNode
  feed: React.ReactNode
}) {
  return (
    <html>
      <body>
        {modal}
        <main>
          {children}
          <aside>{feed}</aside>
        </main>
      </body>
    </html>
  )
}

默认文件(必需):

// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

// app/@feed/default.tsx
export default function FeedDefault() {
  return <div>Default Feed</div>
}

参见模板:templates/parallel-routes-with-default.tsx


2. 路由组

使用场景:组织路由,同时不影响 URL 结构。

结构:

app/
├── (marketing)/
│   ├── about/
│   │   └── page.tsx       → /about
│   └── contact/
│       └── page.tsx       → /contact
├── (shop)/
│   ├── products/
│   │   └── page.tsx       → /products
│   └── cart/
│       └── page.tsx       → /cart
└── layout.tsx

组间使用不同布局:

app/
├── (marketing)/
│   ├── layout.tsx          ← Marketing layout
│   └── about/page.tsx
├── (shop)/
│   ├── layout.tsx          ← Shop layout
│   └── products/page.tsx
└── layout.tsx              ← Root layout

参见参考:references/app-router-fundamentals.md


React 19.2 功能

Next.js 16 集成了 React 19.2,其中包含 React Canary 的新功能。

1. 视图过渡

使用场景:在页面切换之间实现流畅动画。

'use client'

import { useRouter } from 'next/navigation'
import { startTransition } from 'react'

export function NavigationLink({ href, children }: { href: string; children: React.ReactNode }) {
  const router = useRouter()

  function handleClick(e: React.MouseEvent) {
    e.preventDefault()

    // Wrap navigation in startTransition for View Transitions
    startTransition(() => {
      router.push(href)
    })
  }

  return <a href={href} onClick={handleClick}>{children}</a>
}

结合 CSS View Transitions API:

/* app/globals.css */
@view-transition {
  navigation: auto;
}

/* Animate elements with view-transition-name */
.page-title {
  view-transition-name: page-title;
}

参见模板:templates/view-transitions-react-19.tsx


2. useEffectEvent()(实验性)

使用场景:从 useEffect 中提取非响应式逻辑。

'use client'

import { useEffect, experimental_useEffectEvent as useEffectEvent } from 'react'

export function ChatRoom({ roomId }: { roomId: string }) {
  const onConnected = useEffectEvent(() => {
    console.log('Connected to room:', roomId)
  })

  useEffect(() => {
    const connection = connectToRoom(roomId)
    onConnected() // Non-reactive callback

    return () => connection.disconnect()
  }, [roomId]) // Only re-run when roomId changes

  return <div>Chat Room {roomId}</div>
}

使用原因:当回调依赖项发生变化时,避免不必要地重新运行 useEffect。


3. React Compiler(稳定版)

使用场景:无需 useMemo、useCallback 即可自动记忆化。

在 next.config.ts 中启用:

import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    reactCompiler: true,
  },
}

export default config

安装插件:

npm install babel-plugin-react-compiler

示例(无需手动记忆化):

'use client'

export function ExpensiveList({ items }: { items: string[] }) {
  // React Compiler automatically memoizes this
  const filteredItems = items.filter(item => item.length > 3)

  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  )
}

参见参考:references/react-19-integration.md


Metadata API

Metadata API 提供类型安全的 SEO 和社交分享元数据。

1. 静态元数据

模式:从页面或布局导出 metadata 对象。

// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My App',
  description: 'Welcome to my app',
  openGraph: {
    title: 'My App',
    description: 'Welcome to my app',
    images: ['/og-image.jpg'],
  },
  twitter: {
    card: 'summary_large_image',
    title: 'My App',
    description: 'Welcome to my app',
    images: ['/twitter-image.jpg'],
  },
}

export default function Page() {
  return <h1>Home</h1>
}

2. 动态元数据

模式:导出 generateMetadata 异步函数。

// app/posts/[id]/page.tsx
import type { Metadata } from 'next'

export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.coverImage],
    },
  }
}

export default async function PostPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return <article>{post.content}</article>
}

3. Sitemap

文件:app/sitemap.ts

import type { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await fetch('/api/posts').then(r => r.json())

  const postUrls = posts.map((post: { id: string; updatedAt: string }) => ({
    url: `https://example.com/posts/${post.id}`,
    lastModified: post.updatedAt,
    changeFrequency: 'weekly' as const,
    priority: 0.8,
  }))

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postUrls,
  ]
}

参见模板:templates/metadata-config.ts 参见参考:references/metadata-api-guide.md


图片与字体优化

1. next/image

基本用法:

import Image from 'next/image'

export function MyImage() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero image"
      width={1200}
      height={600}
      priority // Load above the fold
    />
  )
}

响应式图片:

<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  style={{ objectFit: 'cover' }}
  sizes="(max-width: 768px) 100vw, 50vw"
/>

远程图片(在 next.config.ts 中配置):

import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
}

export default config

参见模板:templates/image-optimization.tsx


2. next/font

Google Fonts:

// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  )
}

本地字体:

import localFont from 'next/font/local'

const myFont = localFont({
  src: './fonts/my-font.woff2',
  display: 'swap',
  variable: '--font-my-font',
})

参见模板:templates/font-optimization.tsx


性能模式

1. 懒加载

组件懒加载:

import dynamic from 'next/dynamic'

const HeavyComponent = dynamic(() => import('./heavy-component'), {
  loading: () => <div>Loading...</div>,
  ssr: false, // Disable SSR for client-only components
})

export default function Page() {
  return (
    <div>
      <h1>My Page</h1>
      <HeavyComponent />
    </div>
  )
}

条件加载:

'use client'

import { useState } from 'react'
import dynamic from 'next/dynamic'

const Chart = dynamic(() => import('./chart'), { ssr: false })

export function Dashboard() {
  const [showChart, setShowChart] = useState(false)

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && <Chart />}
    </div>
  )
}

2. 代码拆分

路由级拆分(自动):

app/
├── page.tsx       → Bundles: /, shared
├── about/
│   └── page.tsx   → Bundles: /about, shared
└── products/
    └── page.tsx   → Bundles: /products, shared

组件级拆分(使用 dynamic import):

const Analytics = dynamic(() => import('./analytics'))
const Comments = dynamic(() => import('./comments'))

export default function BlogPost() {
  return (
    <article>
      <h1>Post Title</h1>
      <p>Content...</p>
      <Analytics /> {/* Separate bundle */}
      <Comments />  {/* Separate bundle */}
    </article>
  )
}

3. Turbopack(在 Next.js 16 中稳定)

默认情况:Turbopack 现在是 Next.js 16 的默认打包器。

指标:

  • 生产构建速度提升 2–5×
  • Fast Refresh 速度最高提升 10×

退出使用(如有需要):

npm run build -- --webpack

启用文件系统缓存(Beta):

// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    turbopack: {
      fileSystemCaching: true, // Beta: Persist cache between runs
    },
  },
}

export default config

参见参考:references/performance-optimization.md


TypeScript 配置

1. 严格模式

在 tsconfig.json 中启用严格模式:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

2. 路径别名

在 tsconfig.json 中配置:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./app/*"],
      "@/components/*": ["./app/components/*"],
      "@/lib/*": ["./lib/*"],
      "@/styles/*": ["./styles/*"]
    }
  }
}

用法:

// Instead of: import { Button } from '../../../components/button'
import { Button } from '@/components/button'

3. 类型安全的路由

根据路由生成类型:

npm run build

用法:

import { useRouter } from 'next/navigation'

const router = useRouter()

// Type-safe routing
router.push('/posts/123') // ✅ Valid route
router.push('/invalid')   // ❌ Type error if route doesn't exist

参见参考:references/typescript-configuration.md


常见错误与解决方案

1. 错误:params 是 Promise

错误:

Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'

原因:Next.js 16 将 params 改为异步。

解决方案:等待 params:

// ❌ Before
export default function Page({ params }: { params: { id: string } }) {
  const id = params.id
}

// ✅ After
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
}

2. 错误:searchParams 是 Promise

错误:

Property 'query' does not exist on type 'Promise<{ query: string }>'

原因:在 Next.js 16 中,searchParams 现在是异步的。

解决方案:

// ❌ Before
export default function Page({ searchParams }: { searchParams: { query: string } }) {
  const query = searchParams.query
}

// ✅ After
export default async function Page({ searchParams }: { searchParams: Promise<{ query: string }> }) {
  const { query } = await searchParams
}

3. 错误:cookies() 需要使用 await

错误:

'cookies' implicitly has return type 'any'

原因:cookies() 在 Next.js 16 中变为异步函数。

解决方案:

// ❌ Before
import { cookies } from 'next/headers'

export function MyComponent() {
  const cookieStore = cookies()
}

// ✅ After
import { cookies } from 'next/headers'

export async function MyComponent() {
  const cookieStore = await cookies()
}

4. 错误:并行路由缺少 default.js

错误:

Error: Parallel route @modal/login was matched but no default.js was found

原因:Next.js 16 要求所有并行路由都必须有 default.js。

解决方案:添加 default.tsx 文件:

// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

5. 错误:revalidateTag() 需要 2 个参数

错误:

Expected 2 arguments, but got 1

原因:在 Next.js 16 中,revalidateTag() 现在需要一个 cacheLife 参数。

解决方案:

// ❌ Before
revalidateTag('posts')

// ✅ After
revalidateTag('posts', 'max')

6. 错误:无法在 Server Component 中使用 React 钩子

错误:

You're importing a component that needs useState. It only works in a Client Component

原因:在 Server Component 中使用了 React 钩子。

解决方案:添加 'use client' 指令:

// ✅ Add 'use client' at the top
'use client'

import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

7. 错误:middleware.ts 已弃用

警告:

Warning: middleware.ts is deprecated. Use proxy.ts instead.

解决方案:迁移到 proxy.ts:

// Rename: middleware.ts → proxy.ts
// Rename function: middleware → proxy

export function proxy(request: NextRequest) {
  // Same logic
}

8. 错误:Turbopack 构建失败

错误:

Error: Failed to compile with Turbopack

原因:Turbopack 现在是 Next.js 16 的默认构建工具。

解决方案:如果不兼容,请选择退出使用 Turbopack:

npm run build -- --webpack

9. 错误:next/image src 无效

错误:

Invalid src prop (https://example.com/image.jpg) on `next/image`. Hostname "example.com" is not configured under images in your `next.config.js`

解决方案:在 next.config.ts 中添加远程模式:

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
      },
    ],
  },
}

10. 错误:无法将 Server Component 导入 Client Component

错误:

You're importing a Server Component into a Client Component

解决方案:将 Server Component 作为 children 传递:

// ❌ Wrong
'use client'
import { ServerComponent } from './server-component' // Error

export function ClientComponent() {
  return <ServerComponent />
}

// ✅ Correct
'use client'

export function ClientComponent({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}

// Usage
<ClientComponent>
  <ServerComponent /> {/* Pass as children */}
</ClientComponent>

11. 错误:generateStaticParams 不起作用

原因:generateStaticParams 仅适用于静态生成(export const dynamic = 'force-static')。

解决方案:

export const dynamic = 'force-static'

export async function generateStaticParams() {
  const posts = await fetch('/api/posts').then(r => r.json())
  return posts.map((post: { id: string }) => ({ id: post.id }))
}

12. 错误:fetch() 未缓存

原因:Next.js 16 使用通过 "use cache" 指令启用的缓存。

解决方案:在组件或函数中添加 "use cache":

'use cache'

export async function getPosts() {
  const response = await fetch('/api/posts')
  return response.json()
}

13. 错误:路由组发生路由冲突

错误:

Error: Conflicting routes: /about and /(marketing)/about

原因:路由组生成了相同的 URL 路径。

解决方案:确保路由组之间没有冲突:

app/
├── (marketing)/about/page.tsx  → /about
└── (shop)/about/page.tsx       → ERROR: Duplicate /about

# Fix: Use different routes
app/
├── (marketing)/about/page.tsx     → /about
└── (shop)/store-info/page.tsx     → /store-info

14. 错误:元数据未更新

原因:使用动态元数据时未提供 generateMetadata()。

解决方案:对动态页面使用 generateMetadata():

export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return {
    title: post.title,
    description: post.excerpt,
  }
}

15. 错误:next/font 字体未加载

原因:字体变量未应用到 HTML 元素。

解决方案:将字体变量应用到 <html> 或 <body>:

import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html className={inter.variable}> {/* ✅ Apply variable */}
      <body>{children}</body>
    </html>
  )
}

16. 错误:浏览器中无法使用环境变量

原因:仅限服务器端使用的环境变量不会暴露给浏览器。

解决方案:添加 NEXT_PUBLIC_ 前缀以便在客户端使用:

# .env
SECRET_KEY=abc123                  # Server-only
NEXT_PUBLIC_API_URL=https://api    # Available in browser
// Server Component (both work)
const secret = process.env.SECRET_KEY
const apiUrl = process.env.NEXT_PUBLIC_API_URL

// Client Component (only public vars work)
const apiUrl = process.env.NEXT_PUBLIC_API_URL

17. 错误:未找到 Server Action

错误:

Error: Could not find Server Action

原因:缺少 'use server' 指令。

解决方案:添加 'use server':

// ❌ Before
export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

// ✅ After
'use server'

export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

18. 错误:TypeScript 路径别名不起作用

原因:tsconfig.json 中的 baseUrl 或 paths 配置不正确。

解决方案:正确配置:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./app/components/*"]
    }
  }
}

参见参考资料:references/top-errors.md


模板参考

templates/ 中提供了以下模板:

App Router 基础知识:

  • app-router-async-params.tsx - Async params、searchParams 模式(Next.js 16)
  • parallel-routes-with-default.tsx - 带必需的 default.js 的并行路由
  • route-groups-example.tsx - 路由组组织方式

缓存组件(Next.js 16):

  • cache-component-use-cache.tsx - 使用 "use cache" 的缓存组件
  • partial-prerendering.tsx - 含静态和动态部分的 PPR
  • revalidate-tag-cache-life.ts - 更新后的 revalidateTag() API
  • server-action-update-tag.ts - 用于读后写一致性的 updateTag()

服务端组件:

  • server-component-data-fetching.tsx - 数据获取模式
  • server-component-streaming.tsx - 使用 Suspense 进行流式传输
  • server-component-composition.tsx - 服务端组件与客户端组件的组合

服务端操作:

  • server-actions-form.tsx - 使用服务端操作处理表单
  • server-actions-validation.ts - 使用 Zod 验证服务端操作
  • server-actions-optimistic.tsx - 乐观更新

路由处理程序:

  • route-handler-api.ts - 基本 CRUD API
  • route-handler-webhook.ts - Webhook 处理
  • route-handler-streaming.ts - 流式响应

Proxy 与中间件:

  • proxy-migration.ts - 从 middleware.ts 迁移到 proxy.ts
  • proxy-auth.ts - 使用 proxy.ts 进行身份验证

React 19.2:

  • view-transitions-react-19.tsx - View Transitions API
  • use-effect-event.tsx - useEffectEvent() 模式
  • react-compiler-example.tsx - React Compiler 用法

元数据:

  • metadata-config.ts - 静态和动态元数据
  • sitemap.ts - 站点地图生成
  • robots.ts - robots.txt 生成

优化:

  • image-optimization.tsx - next/image 模式
  • font-optimization.tsx - next/font 模式
  • lazy-loading.tsx - 动态导入和延迟加载
  • code-splitting.tsx - 代码拆分策略

TypeScript:

  • typescript-config.json - 推荐的 TypeScript 配置
  • path-aliases.tsx - 路径别名用法

配置:

  • next.config.ts - 完整的 Next.js 配置
  • package.json - Next.js 16 的推荐依赖

其他资源

捆绑的参考资料(位于 references/):

  • next-16-migration-guide.md - 从 Next.js 15 完整迁移到 16
  • cache-components-guide.md - 缓存组件深入指南
  • proxy-vs-middleware.md - Proxy.ts 与 middleware.ts 对比
  • async-route-params.md - Async params、searchParams、cookies()、headers()
  • app-router-fundamentals.md - App Router 概念和模式
  • server-components-patterns.md - 服务端组件最佳实践
  • server-actions-guide.md - 服务端操作模式和验证
  • route-handlers-reference.md - 路由处理程序 API 参考
  • metadata-api-guide.md - Metadata API 完整指南
  • performance-optimization.md - 性能模式和 Turbopack
  • react-19-integration.md - Next.js 中的 React 19.2 功能
  • top-errors.md - 18 个以上常见错误及解决方案

脚本:

  • scripts/check-versions.sh - 验证 Next.js 和依赖项版本

外部文档:


版本兼容性

软件包最低版本推荐版本
Next.js16.0.016.0.0+
React19.2.019.2.0+
Node.js20.9.020.9.0+
TypeScript5.1.05.7.0+
Turbopack(内置)稳定版

检查版本:

./scripts/check-versions.sh

Token 效率

预计节省 Token:65-70%

不使用技能(根据文档手动配置):

  • 阅读 Next.js 16 迁移指南:约 5k 个 token
  • 阅读 App Router 文档:约 8k 个 token
  • 阅读 Server Actions 文档:约 4k 个 token
  • 阅读 Metadata API 文档:约 3k 个 token
  • 反复试错修复:约 8k 个 token
  • 总计:约 28k 个 token

使用技能:

  • 加载技能:约 8k 个 token
  • 使用模板:约 2k 个 token
  • 总计:约 10k 个 token
  • 节省:约 18k 个 token(约 64%)

避免的错误:18+ 个常见错误 = 100% 错误预防


维护

上次验证:2025-10-24 下次审查:2026-01-24(每季度) 维护者:Jezweb | [email protected] 代码仓库:https://github.com/jezweb/claude-skills

更新触发条件:

  • Next.js 主要或次要版本发布
  • React 主要版本发布
  • API 中的破坏性变更
  • 新的 Turbopack 功能

版本检查:

cd skills/nextjs
./scripts/check-versions.sh

SKILL.md 结束

评论

支持 Markdown