Next.js 16 已经发布。这绝不是一个“小修小补”的版本更新。Turbopack 终于进入稳定阶段,React Compiler 被直接内置,路由系统变得更加智能,缓存 API 也提供了更精细的控制——许多长期困扰开发者的痛点,在这次更新中都得到了正面解决。
本文将用直观的方式,梳理 Next.js 16 的关键特性、对应示例,以及你必须了解的破坏性变更。
Turbopack 稳定且成为默认打包器
Turbopack 在开发与生产环境均已达到稳定状态,并已成为所有新应用的默认打包器。数据表明,在 Next.js 15.3+ 版本上,已有超过 50% 的开发会话和 20% 的生产构建在使用 Turbopack。这意味着,它不再是未来的构想,而是当前正在被广泛使用的成熟工具。
如果你仍需使用 webpack,可以通过以下命令切换:
next dev --webpack
next build --webpack
然而,使用 Turbopack 将带来以下显著的性能收益:
- 生产构建速度提升 2–5 倍
- Fast Refresh 速度最快提升 10 倍
- 近乎零配置即可上手
Turbopack 文件系统缓存(Beta):项目重启后构建更快
Turbopack 现在支持在开发环境中启用文件系统缓存。它会将构建产物写入磁盘,从而在项目重启时避免从零开始编译,显著缩短编译时间。这对于 Monorepo 项目来说,体验提升尤为明显。
配置方式如下:
const nextConfig = {
experimental: {
turbopackFileSystemCacheForDev: true,
},
};
Vercel 内部应用已经在使用此特性,并观察到了明显的性能提升。如果你经常被“重启后重新编译”所困扰,这个特性值得优先尝试。
create-next-app 更简洁高效
create-next-app 经历了重新设计,流程更简短、界面更干净。其默认模板现在更贴近现代项目的常见技术栈组合:
- 默认启用 App Router
- 优先使用 TypeScript
- 集成 Tailwind CSS
- 集成 ESLint
开发者无需在项目初始化时纠结技术选型,框架直接提供了一个更合理、更现代的起点。这一改进尤其适合希望快速搭建符合现代前端工程化实践项目的开发者。
React Compiler 支持(稳定):自动记忆化
Next.js 16 内置的 React Compiler 支持已进入稳定阶段。其核心价值在于“自动记忆化”:编译器会自动分析并优化组件,开发者无需再手动编写大量的 useMemo 和 useCallback 来避免不必要的重渲染。
启用方式非常简单:
const nextConfig = {
reactCompiler: true,
};
然后安装编译器插件:
npm install babel-plugin-react-compiler@latest
需要注意的是,由于 React Compiler 依赖于 Babel,可能会略微增加构建时间。但权衡之下,它为应用运行时带来的性能收益,在大多数项目中依然是值得的。
全新缓存 API:更精细的控制
Next.js 16 引入了一组更精细的缓存控制 API,允许开发者像工程师一样明确地选择缓存策略,而非完全依赖框架的默认行为。
revalidateTag():必须指定缓存生命周期
revalidateTag() 现在要求必须提供第二个参数 cacheLife profile。这使得开发者可以仅让某个页面片段对应的缓存失效,而不是清空整个页面的缓存。
// 大多数场景的推荐写法
revalidateTag(‘blog-posts’, ‘max’);
// 其他内置 profile
revalidateTag(‘news-feed’, ‘hours’);
revalidateTag(‘analytics’, ‘days’);
// 自定义刷新时间(秒)
revalidateTag(‘products’, { revalidate: 3600 });
官方推荐在多数情况下使用 ‘max’ profile。它会启用“后台再验证”机制:当用户请求命中带 tag 的内容时,会立即返回缓存数据,同时 Next.js 在后台异步刷新数据。这样既保证了响应速度,又确保了数据的更新。
此特性特别适合博客文章、数据分析面板、仪表盘等不需要实时更新,但要求访问流畅的内容。
updateTag():专为 Server Actions 设计,实现“写后即读”
updateTag() 是 Server Actions 的专用 API,旨在提供“写后即读”的语义。它能在同一次请求中使特定缓存立即失效并刷新,确保用户操作后能立刻看到更新,避免“数据已保存但页面仍显示旧内容”的尴尬。
‘use server’;
import { updateTag } from ‘next/cache’;
export async function updateUserProfile(userId, profile) {
await db.users.update(userId, profile);
updateTag(`user-${userId}`);
}
它与 revalidateTag() 的关键区别在于时效性:revalidateTag() 偏向于后台异步更新,而 updateTag() 追求立即可见。因此,它非常适合用户设置、个人资料编辑、需要即时反馈的仪表盘等场景。
refresh():仅刷新未缓存的数据
refresh() 同样是 Server Actions 专用 API,用于刷新那些未被缓存的数据,且不会触动现有的缓存。这使得页面的静态部分能够保持高速,仅动态部分得到更新。
‘use server’;
import { refresh } from ‘next/cache’;
export async function markNotificationAsRead(notificationId) {
await db.notifications.markAsRead(notificationId);
refresh();
}
它非常适合处理通知角标、购物车商品数量、实时指标等场景:页面主体结构稳定,而局部动态数据随时可更新。它可以与客户端的 router.refresh() 互补,让开发者根据数据流选择最合适的刷新策略。
Build Adapters API(Alpha):构建流程可插拔
Next.js 16 提供了一个实验性的 Build Adapters API。开发者可以编写自定义的 adapter,将 Next.js 的构建输出过程接入自己的部署基础设施中。
const nextConfig = {
experimental: {
adapterPath: require.resolve(‘./my-adapter.js’),
},
};
这意味着部署变得前所未有的灵活。你可以轻松地将应用部署到 Cloudflare Workers,将静态资源上传到自定义的 S3 桶,或者接入公司内部的私有平台。这一步标志着 Next.js 正从一个“框架”向一个“模块化平台”演进。
路由与导航:大幅优化,更智能高效
本次更新对路由系统进行了重大改造,页面切换更轻量、快速,且更符合真实的用户交互模式。
Layout 去重下载
当你预取多个共享同一布局的 URL 时,该布局文件只会被下载一次,而不是每个链接都重复下载。例如,一个包含50个商品链接的商品列表页,现在只需下载一次共享布局,节省了大量网络开销。
增量预取
Next.js 现在只会预取那些缓存中尚不存在的部分,并且其行为像一个具有优先级的智能系统:
- 链接离开视口时会取消预取请求
hover 时获得最高的预取优先级
- 数据失效时会触发重新预取
- 能与 Cache Components 无缝协作
虽然这可能意味着更细碎的请求数量,但总体传输体积会显著下降,而且开发者无需修改任何代码即可获得这些优化。
Cache Components 与 PPR:实验性标志移除
Next.js 16 移除了实验性的 PPR 标志,PPR 的功能正在被整合进 Cache Components 中。
const nextConfig = {
experimental: {
cacheComponents: true,
},
};
PPR 的核心思想是:先流式发送静态内容,让页面骨架快速呈现;然后异步注入动态内容。与 Cache Components 结合后,框架能更智能地判断哪些组件应该被缓存,从而实现更优的性能。
重要提示:如果你当前的项目依赖于 experimental.ppr = true,建议暂时停留在当前的 Next.js Canary 版本,等待官方发布稳定的迁移指南。
集成 React 19.2
Next.js 16 使用了最新的 React Canary,并集成了 React 19.2 的特性,包括:
- View Transitions:在状态变更或页面导航时,为更新的元素提供平滑的动画过渡。
- useEffectEvent():允许你将 Effect 中那些不应作为响应式依赖的逻辑抽离出来复用。
<Activity/>:使用 display: none 来隐藏 UI 组件,同时保留其内部状态,非常适合“后台运行”的活动场景。
这些能力为构建具有复杂交互、高性能且易于维护的应用提供了新的解决方案。
破坏性变更与升级须知
版本要求
- Node.js 20.9+(不再支持 Node.js 18)
- TypeScript 5.1.0+
- 浏览器:Chrome 111+、Edge 111+、Firefox 111+、Safari 16.4+
关键移除项
- AMP 支持被完全移除。
next lint 命令被移除。请直接使用 ESLint CLI 运行。可以使用 codemod 迁移:npx @next/codemod@canary next-lint-to-eslint-cli。
- Runtime Configs 被移除,请改用
.env 文件管理环境变量。
experimental.ppr 标志被移除,请改用 experimental.cacheComponents。
- 同步读取
params, searchParams, cookies, headers, draftMode 现在需要使用 await。
- 当
next/image 组件的本地 src 带有查询字符串时,现在需要配置 images.localPatterns。
行为变化
- Turbopack 成为默认打包器(可使用
--webpack 切换)。
images.minimumCacheTTL:默认值从 60 秒改为 4 小时。
images.imageSizes:默认尺寸中移除了 16px。
images.qualities:默认值从 [1..100] 改为 [75]。
images.dangerouslyAllowLocalIP:默认阻止本地 IP 地址的图片优化。
images.maximumRedirects:从不限制改为最多 3 次重定向。
revalidateTag():现在必须提供第二个参数。
- Parallel routes:所有插槽现在都需要显式的
default.js 文件。
dev 与 build 使用不同的输出目录。
- 终端输出信息格式被重构,更加清晰。
- Turbopack 在检测到 Babel 配置时会自动启用。
- Sass:
sass-loader 升级到 v16(使用现代 API)。
弃用项
middleware.ts:建议重命名为 proxy.ts,以更清晰地表达其网络代理和路由拦截的职责。
next/legacy/image:请改用 next/image。
images.domains:请改用 images.remotePatterns。
revalidateTag() 的单参数形式:请改用双参数形式或 updateTag()。
其他改进
next dev 与 next start 进行了性能优化。
next.config.ts 开始支持 Node 原生 TypeScript(需配合 --experimental-next-config-strip-types 标志使用)。
这些改进可能不会成为头条新闻,但它们会持续提升开发者的日常体验——而流畅的体验,正是开发者选择并坚持使用一个框架的关键。
总结与升级指南
Next.js 16 充满了务实的优化:新的缓存 API 旨在解决实际业务中的缓存难题,路由切换的体验接近“瞬时完成”,Turbopack 将性能红利带给绝大多数用户。官方还表示,在即将到来的 Next.js Conf 之前会有更多新内容发布。
现在就可以开始测试 Beta 版本,提前将这些新能力转化为你的开发实践。
准备升级?请参考以下命令:
# 自动升级(推荐)
npx @next/codemod@canary upgrade beta
# 手动升级
npm install next@beta react@latest react-dom@latest
# 创建新项目
npx create-next-app@beta