关于 nextjs
nextjs skill 为使用 Next.js App Router 的开发者整理 Next.js 16 与 React 19.2 的生产实践,重点说明破坏性变更、缓存 API、迁移和错误处理。
主要功能
- 01Next.js 16 迁移指南
- 02异步路由参数处理
- 03Cache Components 与缓存 API
- 04Proxy 和并行路由配置
- 05常见错误及解决方案
适用场景
- 01将项目从 Next.js 15 迁移至 16
- 02为 App Router 配置缓存
- 03排查并行路由或异步参数错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ovachiever/ droid-tings --skill nextjs安装后在 Claude Code 中输入/nextjs确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.md.claude-plugin/plugin.jsonreferences/next-16-migration-guide.mdtop-errors.mdscripts/check-versions.shtemplates/app-router-async-params.tsxcache-component-use-cache.tsxpackage.jsonparallel-routes-with-default.tsxproxy-migration.tsroute-handler-api.tsserver-actions-form.tsx详细介绍
Next.js App Router - 生产模式
版本:Next.js 16.0.0 React 版本:19.2.0 Node.js:20.9+ 上次验证:2025-10-24
目录
- 何时使用此技能
- 何时不使用此技能
- Next.js 16 重大变更
- 缓存组件与缓存 API
- 路由处理程序(Next.js 16 更新)
- Proxy 与 Middleware
- 并行路由 - 必须提供 default.js
- React 19.2 功能
- Turbopack(在 Next.js 16 中稳定)
- 常见错误与解决方案
- 模板与资源
何时使用此技能
重点:Next.js 16 的重大变更和知识盲区(2024 年 12 月及之后)。
在以下情况下使用此技能:
- Next.js 16 重大变更(异步 params、proxy.ts、并行路由 default.js、已移除的功能)
- 使用
"use cache"指令的 缓存组件(Next.js 16 新增) - 新缓存 API:
revalidateTag()、updateTag()、refresh()(在 Next.js 16 中更新) - 从 Next.js 15 迁移到 16(避免重大变更导致的错误)
- 异步路由参数(
params、searchParams、cookies()、headers()现在均为异步) - 包含 default.js 的并行路由(Next.js 16 中必需)
- React 19.2 功能(视图过渡、
useEffectEvent()、React Compiler) - Turbopack(在 Next.js 16 中稳定并作为默认选项)
- 图像默认设置已变更(Next.js 16 中的 TTL、尺寸和质量)
- 错误预防(18 个以上有文档记录的 Next.js 16 错误及解决方案)
何时不使用此技能
以下情况请勿使用此技能:
- 部署到 Cloudflare Workers → 请改用
cloudflare-nextjs技能 - Pages Router 模式 → 此技能仅涵盖 App Router(Pages Router 已过时)
- 身份验证库 → 请改用
clerk-auth、better-auth或其他特定于身份验证的技能 - 数据库集成 → 请改用
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 身份验证(可与此技能组合使用)
- better-auth:用于集成 Better Auth(可与此技能组合使用)
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.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
Cache Components 与缓存 API
Next.js 16 新增:Cache Components 通过 "use cache" 指令引入选择性启用的缓存,取代 Next.js 15 中的隐式缓存。
1. 概述
变更内容:
- Next.js 15:隐式缓存(默认缓存所有服务器组件)
- Next.js 16:选择启用缓存,使用
"use cache"指令
变更原因:显式缓存让开发者拥有更多控制权,并使缓存行为更可预测。
Cache Components 支持:
- 组件级缓存(缓存特定组件,而不是整个页面)
- 函数级缓存(缓存开销较大的计算)
- 页面级缓存(有选择地缓存整个页面)
- Partial Prerendering(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. Partial Prerendering(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 配置),以实现过期后重新验证行为。
之前(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
}
内置 Cache Life 配置:
'max'——最长过期时间(推荐用于大多数场景)'hours'——数小时后过期'days'——数天后过期'weeks'——数周后过期'default'——默认缓存行为
自定义 Cache Life 配置:
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():过期后重新验证(显示过期数据,并在后台重新验证)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():重新验证带有特定标签的数据(过期后重新验证)updateTag():立即使带有特定标签的数据过期并刷新
参见参考资料:references/cache-components-guide.md
路由处理程序(Next.js 16 更新)
路由处理程序中的异步 Params(重大变更)
重要:在 Next.js 16 路由处理程序中,params 和 headers() 现在是异步的。
示例:
// app/api/posts/[id]/route.ts
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params // ✅ Await params in Next.js 16
const headersList = await headers() // ✅ Await headers in Next.js 16
const post = await db.posts.findUnique({ where: { id } })
return NextResponse.json(post)
}
参见模板:templates/route-handler-api.ts
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
并行路由 - 必须提供 default.js(重大变更)
Next.js 16 中的重大变更:并行路由现在必须显式提供 default.js 文件。
结构:
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/@modal/default.tsx
export default function ModalDefault() {
return null // or <Skeleton /> or redirect
}
必需原因:Next.js 16 更改了软导航的处理方式。若没有 default.js,客户端导航时未匹配的插槽会报错。
参见模板:templates/parallel-routes-with-default.tsx
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
Turbopack(在 Next.js 16 中已稳定)
新增:Turbopack 现已成为 Next.js 16 中的默认打包器。
性能提升:
- 生产构建速度提升 2–5 倍
- Fast Refresh 速度最高提升 10 倍
选择退出(如有需要):
npm run build -- --webpack
启用文件系统缓存(实验性):
// next.config.ts
import type { NextConfig } from 'next'
const config: NextConfig = {
experimental: {
turbopack: {
fileSystemCaching: true, // Beta: Persist cache between runs
},
},
}
export default config
常见错误与解决方案
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'
原因:在 Next.js 16 中,cookies() 现在是异步的。
解决方案:
// ❌ 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 Hooks
错误:
You're importing a component that needs useState. It only works in a Client Component
原因:在 Server Component 中使用了 React Hooks。
解决方案:添加 '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 作为子元素传递:
// ❌ 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. 错误:Route Group 路由冲突
错误:
Error: Conflicting routes: /about and /(marketing)/about
原因:Route Group 创建了相同的 URL 路径。
解决方案:确保 Route Group 之间不存在冲突:
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
模板与资源
Next.js 16 专用模板(位于 templates/):
app-router-async-params.tsx- 异步 params 迁移模式parallel-routes-with-default.tsx- 必需的 default.js 文件cache-component-use-cache.tsx- 使用"use cache"的 Cache Componentsrevalidate-tag-cache-life.ts- 使用 cacheLife 更新后的revalidateTag()server-action-update-tag.ts- 用于读后写一致性的updateTag()proxy-migration.ts- 从 middleware.ts 迁移到 proxy.tsview-transitions-react-19.tsx- React 19.2 View Transitionsnext.config.ts- Next.js 16 配置
内置参考文档(位于 references/):
next-16-migration-guide.md- 完整的 Next.js 15→16 迁移指南cache-components-guide.md- Cache Components 深入介绍proxy-vs-middleware.md- Proxy.ts 与 middleware.ts 的比较async-route-params.md- 异步 params 破坏性变更详情react-19-integration.md- Next.js 16 中的 React 19.2 功能top-errors.md- 18 个以上常见错误及解决方案
外部文档:
- Next.js 16 博客:https://nextjs.org/blog/next-16
- Next.js 文档:https://nextjs.org/docs
- Context7 MCP:
/websites/nextjs,获取最新参考资料
版本兼容性
| 包 | 最低版本 | 推荐版本 |
|---|---|---|
| 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%
不使用 Skill(根据文档手动配置):
- 阅读 Next.js 16 迁移指南:约 5k tokens
- 阅读 App Router 文档:约 8k tokens
- 阅读 Server Actions 文档:约 4k tokens
- 阅读 Metadata API 文档:约 3k tokens
- 反复试错修复:约 8k tokens
- 总计:约 28k tokens
使用 Skill:
- 加载 Skill:约 8k tokens
- 使用模板:约 2k tokens
- 总计:约 10k tokens
- 节省:约 18k tokens(约 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 结束