我的Next.js项目升级到16之后,dev倒是快了,但build差点让我回退

先说结论:Next.js 16值得升,但升级过程的折腾程度远超我的预期。

事情是这样的。我有个跑了大半年的Next.js项目,之前一直用webpack做打包,偶尔开--turbopack跑dev,体验确实不错。看到16正式版的changelog写着"Turbopack稳定,推荐升级",我想着反正迟早要迁,不如趁现在没什么业务压力先搞定。 结果升级第一步就给了我一巴掌。

Turbopack成了默认,我的webpack配置不认了

跑完npx @next/codemod@canary upgrade latest,满心以为会像以前一样顺滑。然后CI直接红了。 报错很直白:检测到自定义webpack配置,拒绝build。 不是我配置写得有问题,是Turbopack现在根本不想搭理webpack了------它接管了打包流程,碰到自定义webpack配置直接报错,生怕你稀里糊涂跑出不兼容的产物。而我那个next.config.js里恰好有一段接Sentry时加的webpack fallback配置,跑了一直没动过,这次直接成了绊脚石。 官方的建议是先加--turbopack标志强制走新流程,或者加--webpack暂时回退。我选了前者,把CI先救活再说。build总算过了,心想最难的应该已经搞定了。结果dev一跑,页面白屏。

params变成了Promise,我整个页面都挂了

控制台报的是params.slug is not iterable。我的博客详情页写法在Next.js 15里跑了大半年没出过任何问题:

javascript 复制代码
export default async function Page({ params }: { params: { slug: string } }) {
  const { slug } = params
  // ...
}

到了16,params变成了Promise。不是建议你用await,是你不用await就报错。searchParamscookies()headers()draftMode()这些也全是Promise了------官方说"同步访问已完全移除",一点余地不留。

好在官方有codemod:

swift 复制代码
npx @next/codemod@canary next-async-dynamic-apis .

跑了一遍,大部分页面自动改好了。改完长这样:

javascript 复制代码
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  // ...
}

我松了口气,在本地多点了几个页面,都没问题。心想这升级也没网上说的那么恐怖嘛。 然后测试环境一部署,CSS又炸了。

Sass里的~前缀,Turbopack不认

报错是Can't resolve '~bootstrap/dist/css/bootstrap.min.css'。webpack时代用~前缀来引用node_modules里的样式,大家都这么写,Turbopack不认这个语法,只接受标准路径。

项目里引用了一堆第三方库的样式,挨个手动改太烦。Turbopack倒是给了个兼容方案:

css 复制代码
const nextConfig: NextConfig = {
  turbopack: {
    resolveAlias: {
      '~*': '*',
    },
  },
}

用resolveAlias把~映射掉。不过官方文档也写了,建议还是把代码里的~去掉,毕竟alias hack早晚要还。我想着既然都改了,干脆全部替换掉,也就几分钟的事。 改完,本地再跑,一切正常。我甚至开始跟同事说"升级搞定了,就那样吧"。 然后部署又挂了。

Node版本也得跟着升

CI机器跑的是Node 18,Next.js 16要求>= 20.9.0。报错就一行:

vbnet 复制代码
Error: Next.js 16 requires Node.js >= 20.9.0

升级公告里确实写了这个要求,但我之前每次升Next.js都没在Node版本上栽过跟头,注意力全放在框架本身的breaking changes上了。结果这次不光Node要升,TypeScript也得5.1.0以上,我们有个老项目还停在5.0。 升个Next.js连带着把运行环境和编译器都升了一遍。这算是这次升级最容易被忽略的点------你盯着框架的迁移指南看,却忘了底下还有一整条工具链等着。

一些没用到的变化

Next.js 16还把middleware.ts改成了proxy.ts,导出名也从middleware变成handler。这个我们项目没用middleware,没踩到坑。但如果你的项目有自定义middleware,记得跑codemod的时候一起处理了,或者手动改。

折腾完了,说说值不值

整个升级过程花了大半天。最让人烦躁的不是哪个具体的bug,而是一种"以为搞定了结果又冒出来一个"的循环感------webpack改完、async改了、Sass改了,每个单拎出来都不复杂,但叠在一起就很消磨耐心。

不过话说回来,跑起来之后确实快得明显。dev服务器启动从之前起身倒杯水的功夫变成了几乎瞬间就绪,HMR热更新也感觉不到延迟了。这种体验上的提升是实实在在的。

新项目直接上Next.js 16没问题。老项目的话,升级之前先跑一遍codemod dry run看看会改哪些文件,重点关注这几样:webpack自定义配置、Async APIs(params/searchParams/cookies/headers)、Sass的tilde导入、Node和TypeScript版本、以及有没有middleware需要改proxy。

对了,这次升级最大的感受倒不是技术上的,而是对Next.js方向的判断更清楚了------Turbopack从可选变成默认,意味着Vercel认为它已经成熟到不需要留后路的程度。这种框架级别的决策很果断,作为使用者你能做的就是跟上。

相关推荐
光影少年1 天前
HashRouter 和 BrowserRouter 区别、底层原理、部署差异
前端·react.js·nestjs
kyriewen2 天前
我用 50 行代码重写了 React Router 核心,终于搞懂了前端路由原理
前端·javascript·react.js
ZhengEnCi2 天前
Q02-Vue-React-index.html完全指南
vue.js·react.js·html
weedsfly2 天前
JavaScript 事件流:彻底搞懂捕获、冒泡与事件委托
前端·javascript·react.js
Patrick_Wilson3 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
光影少年4 天前
原生DOM操作在React 中的注意事项
前端·javascript·react.js
YAwu115 天前
深入解析 React 炫彩鼠标跟随标题组件:从坐标定位到动画性能
前端·react.js
Ruihong5 天前
🎉 VuReact 1.9.0 发布,支持 Vue 3.4 defineModel 编译到 React
vue.js·react.js·面试
spmcor5 天前
React 架构师之路:Next.js 全栈革命(第八篇)
前端·react.js