升级迁移是个技术活,终于把博客升级到了最新技术栈。
小麦2025年08月30日1748 字
分享一下我网站两次失败的升级经历、踩过的坑、升级成果以及一些看法。
建站一周年,终于完成了核心技术栈的大版本升级,来做个总结。
项目情况#
去年 8 月份我提交了这个网站的第一行代码,所以差不多算一周年。
这是一个基于 Serverless 架构的 Next.js
框架的全栈项目,前后端代码、工具链、共享依赖、还有一些别的应用均放在同一个 monorepo 仓库中。
这个仓库包含四个 web 站点,但是大家只能看到这一个,目前仓库总代码量是 6w+ 行,算是不大不小。
cloc --exclude-dir=$(tr '\n' ',' < .clocignore) .1055 text files.927 unique files.180 files ignored.github.com/AlDanial/cloc v 2.04 T=0.22 s (4163.5 files/s, 395416.4 lines/s)-------------------------------------------------------------------------------Language files blank comment code-------------------------------------------------------------------------------TypeScript 800 12431 7265 60648JavaScript 35 63 135 2536JSON 40 0 0 1505SCSS 31 236 24 1157Markdown 7 533 0 546CSS 4 102 35 528YAML 5 41 0 237SVG 4 0 0 16Text 1 0 0 1-------------------------------------------------------------------------------SUM: 927 13406 7459 67174-------------------------------------------------------------------------------
版本升级目标如下:
Node.js
: v18 -> v22Next.js
: v14 -> v15React
: v18 -> v19ESLint
: v8 -> v9TailwindCSS
: v3 -> v4
第一次搁置(生态没跟上)#
React 19 于 2024/4/29 发布,Next.js 在同年 10 月份发布了 v15 以支持 React 19。
我的网站在 8 月份启动,因此没赶上最新的 Next.js v15,不过 12 月就有计划做升级。
之前我曾预言大家从 React 18 升级到 19 少则一年多则数年,其中一个很重要的原因就是 React 生态的跟进问题:即依赖 React 或 Next.js 特定版本的三方库是否已经支持较新的版本。
如项目不满足三方依赖的 peerDependencies
设定,会直接导致 npm install 安装失败:
npm error ERESOLVE unable to resolve dependency tree
比如我之前遇到的这三个阻塞问题:
- nextjs-auth0:https://github.com/auth0/nextjs-auth0/pull/1845
- ahooks:https://github.com/alibaba/hooks/issues/2670
- sandpack:https://github.com/codesandbox/sandpack/issues/1236
因此,如果项目依赖越多,那么越难跨大版本升级。
第二次搁置(环境没跟上)#
三方依赖都支持了新版本,是不是就可以顺利升级了呢?并不是,还有一个容易忽略的东西是运行时(Runtime),前端用的是 Node.js。
我的网站最开始部署在国外 Cloudflare,由于合规和发展需要迁回国内做备案,我选择了腾讯云做接入。
为了延续 Serverless 架构,我选择腾讯云的「云函数」作为源站。但是它陈旧的运行时(Node.js v18.15)却成为升级路上的一个阻碍。
技术支持同学建议我用容器服务,但是考虑到 CI/CD 改造、性能和价格问题等问题并没有采纳。
因此升级计划暂时搁置了一段时间。
第三次尝试#
上个月又调研了其他云厂商的函数计算服务,发现阿里云是最理想,他们的环境版本和产品功能是国内最更完备的,因此开始着手从腾讯云迁移到阿里云。
第三次的迁移过程其实比想象中的顺利,因为我有一套自研的 DevOps 工具,只需要添加对阿里云函数的支持。
而访问数据库、AI 服务、日志服务、对象存储、支付服务、消息队列等的业务代码都可以保持不变,和云服务充分解耦。
遇到的问题#
Prisma Query Engine 不兼容#
我的项目使用 Prisma 作为数据库 ORM,它的查询引擎其实是和操作系统相关的,因此在不同的操作系统上使用它就要用到不同的原生模块(.node):
- libquery_engine-darwin-arm64.dylib.node
- libquery_engine-debian-openssl-3.0.x.so.node
- libquery_engine-rhel-openssl-1.1.x.so.node
对于 Serverless 环境来说,不同云服务的所使用的 Linux 发行版是不同的,比如:
- 腾讯云用的是 CentOS,需要依赖
libquery_engine-rhel-openssl-1.1.x.so.node
。 - 阿里云的「自定义运行时」用的是 Debian,需要依赖
libquery_engine-debian-openssl-3.0.x.so.node
。 - 阿里云的「内置运行时」用的是 CentOS,需要依赖
libquery_engine-rhel-openssl-1.1.x.so.node
,然而文档里并没有说明。
Next.js Prefetch 请求判断失效#
Next.js v15 对 rsc 请求头进行了调整,对于 prefetch 请求的判断逻辑需要调整。
// For Next.js v14const isPrefetch =nextHeaders.get('sec-fetch-mode') === 'cors' &&nextHeaders.get('sec-fetch-dest') === 'empty' &&nextHeaders.get('next-url') !== null;// For Next.js v15const isPrefetch =nextHeaders.has('next-router-prefetch') ||nextHeaders.get('purpose') === 'prefetch';
ESLint 配置文件失效#
目前 ESLint 最新版本是 v9,已经不再支持 .eslintrc*
这样的配置文件,只支持 eslint.config.*
。
而且配置结构也变了太多,各种兼容写法让人有点摸不着头脑。
// eslint.config.mjsimport { dirname } from 'path';import { fileURLToPath } from 'url';import { FlatCompat } from '@eslint/eslintrc';const __filename = fileURLToPath(import.meta.url);const __dirname = dirname(__filename);const compat = new FlatCompat({baseDirectory: __dirname,});const eslintConfig = [...compat.extends('next/core-web-vitals', 'next/typescript'),{ignores: ['node_modules/**','.next/**','out/**','build/**','next-env.d.ts',],},{rules: {'@next/next/no-img-element': 'off',},},];export default eslintConfig;
我记得之前 ESLint 的配置都很清晰,不知道为什么要搞得这么奇怪。
// .eslintrc.jsmodule.exports = {extends: ['next/core-web-vitals'],parserOptions: {babelOptions: {presets: [require.resolve('next/babel')],},},rules: {'@next/next/no-img-element': 'off',},};
Tailwind CSS 配置文件失效#
好家伙,大家商量好一起改配置文件是吧。
在 Tailwind CSS v4 中,已经不再需要 tailwind.config.*
了,取而代之的是全部放在 global.css
里,官方管这个叫 CSS-first configuration。
@import "tailwindcss";@theme {--radius-lg: var(--radius);--radius-md: calc(var(--radius) - 2px);--radius-sm: calc(var(--radius) - 4px);...}@layer base {*,::after,::before,::backdrop,::file-selector-button {border-color: var(--color-gray-200, currentcolor);}}
升级成果#
构建性能提升#
Next.js 从 v15.5 开始支持用 Turbopack 进行生产构建(之前是 Webpack),这次升级顺便切到 Turbopack,暂时没发现问题,稳定性还是比较好的。
Github Action 免费版(2核)上的平均构建时间减少 30s,性能提升了 16.67%。
Use Webpack
Use Turbopack
官方数据是 28%(4核),2核的话就是 14%,看来是符合预期的。
部署时间缩短#
从腾讯云迁移到阿里云后,平均部署时间缩短 40s,提升约 35%。
腾讯云函数
阿里云函数计算
总结一下#
升级迁移一个全栈应用要比纯前端应用复杂许多,在涉及到运行环境时,不可避免地会接触到底层系统方面的问题。
在现代前端框架的升级上,依赖管理、生态系统的积极性非常重要。
我曾用 AI 辅助升级迁移,但是发现它有用但不大,那些没有见过的 bug,没有学过的文档都会让它黔驴技穷。
2025 年升级迁移依然是个技术活,虽然可以用 codemod 解决掉 80% 的机械性问题,但是剩下的 20% 才是真正考验综合技术能力的时候。