关于 nextjs
nextjs 技能为使用 Next.js 16 App Router 的开发者提供生产实践参考,涵盖路由、缓存、服务端组件及迁移变化。内容也涉及 React 19.2、性能优化和常见错误。
主要功能
- 01App Router 路由与布局模式
- 02Server Components 和 Server Actions
- 03缓存组件与缓存 API
- 04Next.js 15 到 16 的迁移指导
- 05元数据、图片与字体优化
- 06常见错误与模板参考
适用场景
- 01构建 Next.js 16 App Router 页面
- 02实现服务端数据获取与表单操作
- 03配置缓存和部分预渲染
- 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
目录
- 何时使用此技能
- 何时不使用此技能
- Next.js 16 重大变更
- 缓存组件与缓存 API
- 服务端组件
- 服务端操作
- 路由处理程序
- Proxy 与 Middleware
- 并行路由与路由组
- React 19.2 功能
- 元数据 API
- 图像与字体优化
- 性能模式
- TypeScript 配置
- 常见错误与解决方案
- 模板参考
- 其他资源
何时使用此技能
在以下情况下使用此技能:
- 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 运行时)运行,明确了网络边界。这能更清晰地区分边缘中间件和服务端代理。
迁移步骤:
- 重命名文件:
middleware.ts→proxy.ts - 重命名函数:
middleware→proxy - 更新配置:
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 中已移除:
- AMP 支持 - 已完全移除。请迁移到标准页面。
next lint命令 - 请直接使用 ESLint 或 Biome。serverRuntimeConfig和publicRuntimeConfig- 请改用环境变量。experimental.ppr标志 - 已演进为 Cache Components。请使用"use cache"指令。- 自动应用
scroll-behavior: smooth- 如有需要,请手动添加。 - 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 15 | Next.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>
)
}
规则:
- ✅ 可以直接在组件主体中
awaitPromise - ✅ 可以访问
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- 含静态和动态部分的 PPRrevalidate-tag-cache-life.ts- 更新后的revalidateTag()APIserver-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 APIroute-handler-webhook.ts- Webhook 处理route-handler-streaming.ts- 流式响应
Proxy 与中间件:
proxy-migration.ts- 从 middleware.ts 迁移到 proxy.tsproxy-auth.ts- 使用 proxy.ts 进行身份验证
React 19.2:
view-transitions-react-19.tsx- View Transitions APIuse-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 完整迁移到 16cache-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- 性能模式和 Turbopackreact-19-integration.md- Next.js 中的 React 19.2 功能top-errors.md- 18 个以上常见错误及解决方案
脚本:
scripts/check-versions.sh- 验证 Next.js 和依赖项版本
外部文档:
- Next.js 16 博客:https://nextjs.org/blog/next-16
- Next.js 文档:https://nextjs.org/docs
- React 文档:https://react.dev
- Context7 MCP:使用
/websites/nextjs获取最新的 Next.js 参考资料
版本兼容性
| 软件包 | 最低版本 | 推荐版本 |
|---|---|---|
| Next.js | 16.0.0 | 16.0.0+ |
| React | 19.2.0 | 19.2.0+ |
| Node.js | 20.9.0 | 20.9.0+ |
| TypeScript | 5.1.0 | 5.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 结束