前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

Next.js 16 升级指南 从Turbopack默认启用到异步API全面化

首页2025-11-03 20:40:12Front-End
Next.jsReact前端开发TurbopackReact Compiler升级指南

把一个跑在 Next.js 15 上的 App Router 项目直接装上 next@16,next dev 大概率还能起来,next build 却会直接失败。问题不在业务代码,在 next.config 里那几行自定义 webpack 配置。Next.js 16 把 Turbopack 提成了默认构建器,顺手把 15 时代留下的一堆兼容口子全关了,异步 API 的同步降级、middleware 的文件名、experimental_ppr 的路由级开关,这次一并收走。

这篇按官方升级文档把 16 的改动过了一遍,排序标准只有一个,就是「会不会让你的构建直接红掉」。每条都写清楚改法、为什么这么改、以及什么情况下可以先不动。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • 升级前必须先满足的环境基线,以及 codemod 能帮你干掉多少活
  • Turbopack 默认启用之后,自定义 webpack 配置的三条出路
  • 异步 Request API 彻底移除同步兼容,params / searchParams / id 全都变 Promise
  • React 19.2 与 React Compiler 稳定版怎么开,代价是什么
  • 缓存 API 新增的 updateTag 和 refresh,和老的 revalidateTag 怎么分工
  • middleware 改名 proxy 带来的运行时限制
  • next/image 一口气改掉的七个默认值
  • 其余会让构建失败的零碎改动,以及被移除的功能

# 一、升级前先把环境和退路准备好

Next.js 16 抬高了运行环境的门槛,这一步没过,后面全都白搭。

要求 变化详情
Node.js 最低 20.9.0,且必须是 LTS,Node.js 18 不再支持
TypeScript 最低 5.1.0
浏览器 Chrome 111+、Edge 111+、Firefox 111+、Safari 16.4+

Node 18 被砍掉这条最容易在 CI 上翻车。本地 nvm 里装的是 20,Dockerfile 里的基础镜像还写着 node:18-alpine,本地构建绿了推上去照样挂。升级第一件事是把 CI 镜像、Dockerfile、package.json 里的 engines 字段一起改掉,别只改本地。

浏览器基线抬到 Chrome 111 意味着产物里会直接使用更新的语法特性,如果你的用户群里还有大量老设备,这一条要单独评估,它不像 Node 版本那样有明显报错,只会在特定机型上白屏。

# 官方 codemod 能帮你做的事

Next.js 提供的升级 codemod 覆盖面比很多人以为的要广:

# pnpm
pnpm dlx @next/codemod@canary upgrade latest

# npm
npx @next/codemod@canary upgrade latest

# yarn
yarn dlx @next/codemod@canary upgrade latest

# bun
bunx @next/codemod@canary upgrade latest
@前端进阶之旅: 代码已经复制到剪贴板

它会自动处理这几件事:

  • 把 next.config.js 里的 turbopack 配置改成新写法
  • 从 next lint 迁移到 ESLint CLI
  • 把废弃的 middleware 约定迁移到 proxy
  • 去掉已稳定 API 上的 unstable_ 前缀
  • 移除 layout 和 page 里的 experimental_ppr 配置

跑完 codemod 一定要看 diff。我的经验是它对标准写法处理得很干净,但对那种被包了一层工具函数的动态 API 调用会漏掉,最后还是得自己搜一遍。

# AI 辅助升级

如果你在用支持 MCP 的 AI 编码工具,官方还提供了 Next.js DevTools MCP:

{
  "mcpServers": {
    "next-devtools": {
      "command": "npx",
      "args": ["-y", "next-devtools-mcp@latest"]
    }
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

配好之后直接让助手帮你升级即可。这块我只在小项目上试过,几千个文件的老仓库有没有坑我没验证。

# 手动升级

不想跑 codemod 就手动装:

# pnpm
pnpm add next@latest react@latest react-dom@latest

# npm
npm install next@latest react@latest react-dom@latest

# yarn
yarn add next@latest react@latest react-dom@latest
@前端进阶之旅: 代码已经复制到剪贴板

注意:用 TypeScript 的项目记得同步升 @types/react 和 @types/react-dom,否则异步 params 的类型会一路飘红。

# 二、Turbopack 默认启用后的三条出路

Turbopack 在 16 里正式稳定,next dev 和 next build 默认都走它。以前那个 --turbopack / --turbo 标志可以从脚本里删掉了:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

# 自定义 webpack 配置会让构建失败

这是升级路上第一个真正的拦路虎。项目里只要还有 webpack(config) { ... } 这样的自定义配置,next build 就会直接失败,而不是默默忽略。官方这么设计是有道理的,静默忽略一份配置比报错危险得多,你的 alias、loader、externals 悄无声息地失效,问题会在运行时以最难排查的形态冒出来。

三条出路:

  1. 继续用 Turbopack 但忽略旧配置,跑 next build --turbopack
  2. 把 webpack 配置翻译成 Turbopack 的对应选项,一劳永逸
  3. 退回 webpack,构建脚本加 --webpack 标志
{
  "scripts": {
    "dev": "next dev",
    "build": "next build --webpack",
    "start": "next start"
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

我自己维护的一个站升到 16 之后走的就是第三条,构建脚本里保留了 --webpack。不是说 Turbopack 不行,而是那份 webpack 配置里挂了几个自定义 loader,翻译成本高于收益,先把版本升上去,构建器的迁移单独排期。这种「分两步走」的思路在大项目上比一次性梭哈稳得多。

# 配置从 experimental 提到了顶层

experimental.turbopack 移出实验区,现在是顶层字段:

import type { NextConfig } from 'next'

// Next.js 15 写法
const nextConfig: NextConfig = {
  experimental: {
    turbopack: {},
  },
}

// Next.js 16 写法
const nextConfig: NextConfig = {
  turbopack: {},
}
@前端进阶之旅: 代码已经复制到剪贴板

# 文件系统缓存还在 Beta

Turbopack 现在支持开发模式的文件系统缓存,把编译产物存到磁盘,重启 dev server 之后不用从头编一遍:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    turbopackFileSystemCacheForDev: true,
  },
}
@前端进阶之旅: 代码已经复制到剪贴板

它还挂在 experimental 下面,说明官方自己也没打包票。冷启动慢是 Turbopack 目前最被吐槽的点,这个开关就是冲着它去的,值得开来试试,但别在 CI 上依赖它。

# Sass 的波浪号前缀不能用了

Turbopack 完整支持从 node_modules 导入 Sass,但 webpack 时代那个 ~ 前缀语法不认了:

// Webpack 写法,Turbopack 下报错
@import '~bootstrap/dist/css/bootstrap.min.css';

// 现在的写法
@import 'bootstrap/dist/css/bootstrap.min.css';
@前端进阶之旅: 代码已经复制到剪贴板

这个坑很隐蔽,因为报错信息指向的是找不到文件,第一直觉会去怀疑依赖没装。老项目里的样式文件往往是几年前写的,~ 散落在十几个 .scss 里,全局搜一遍 @import '~ 是最快的办法。

# 三、异步 Request API 这次真的没有退路了

Next.js 15 把 cookies、headers、draftMode 改成异步的时候,留了一个同步访问的过渡期,开发模式下打印警告但不报错。16 把这个口子彻底关掉了。

需要异步访问的完整清单:

  • cookies
  • headers
  • draftMode
  • layout.js、page.js、route.js 里的 params
  • page.js 里的 searchParams
// Next.js 15,过渡期还能这么写
const cookieStore = cookies()

// Next.js 16,必须 await
const cookieStore = await cookies()
@前端进阶之旅: 代码已经复制到剪贴板

为什么非要异步?因为这些值只有在真实请求到来时才能确定,同步读取会强制整棵树在这一点上等住。改成 Promise 之后,React 的并发渲染才能在等待请求信息的同时继续渲染别的分支。关于这套异步化改造的来龙去脉,我在 Next.js 15 新特性完全指南 里写得更细。

回到升级本身,这块强烈建议交给 codemod,手改几百处 await 太容易漏。

# 用 typegen 生成类型助手

异步 params 最烦的不是加 await,是类型。手写 Promise<{ slug: string }> 既啰嗦又容易和路由实际结构对不上。16 里跑一次 npx next typegen,就能拿到全局可用的类型助手:

  • PageProps,页面组件属性
  • LayoutProps,布局组件属性
  • RouteContext,路由上下文
export default async function Page(props: PageProps<'/blog/[slug]'>) {
  const { slug } = await props.params
  const query = await props.searchParams
  return <h1>Blog Post: {slug}</h1>
}
@前端进阶之旅: 代码已经复制到剪贴板

这个设计是真的舒服。路由路径字符串直接当泛型参数,slug 的类型是从文件结构推出来的,改了目录名类型立刻报错,比手写接口靠谱得多。

# 图片元数据和 sitemap 里的参数也变了

容易被漏掉的是这两处。传给 opengraph-image、twitter-image、icon、apple-icon 的 props 现在都是 Promise:

fe
  • 一、升级前先把环境和退路准备好
    • 官方 codemod 能帮你做的事
    • AI 辅助升级
    • 手动升级
  • 二、Turbopack 默认启用后的三条出路
    • 自定义 webpack 配置会让构建失败
    • 配置从 experimental 提到了顶层
    • 文件系统缓存还在 Beta
    • Sass 的波浪号前缀不能用了
  • 三、异步 Request API 这次真的没有退路了
    • 用 typegen 生成类型助手
    • 图片元数据和 sitemap 里的参数也变了
  • 四、React 19.2 与 React Compiler 稳定版
    • React Compiler 转正
  • 五、缓存 API 多了两个入口
    • revalidateTag 支持第二个参数
    • updateTag 解决「改完看不到」
    • refresh 刷新客户端路由
    • cacheLife 和 cacheTag 去掉了前缀
  • 六、路由和导航的改动不用你动手
  • 七、middleware 改名 proxy
  • 八、next/image 一口气改了七个默认值
  • 九、其余会让构建直接失败的改动
    • 并行路由必须有 default.js
    • PPR 换成了 cacheComponents
    • ESLint 与 next lint
    • 滚动行为不再被覆盖
    • dev 和 build 可以并发跑了
    • 三处移除
  • 总结
  • 参考

← pm2 ecosystem部署Node应用与pm2-logrotate日志切割实战TanStack Query 实战指南 缓存机制与 Next.js 集成 →