代码 Nuxt 5 迁移:Options API 被编译出客户端包、路由默认区分大小写、server/utils 子目录不再自动导入

2026-11-02 21:06:40

Nuxt 5 迁移笔记:会静默改变行为的默认值,以及对应的排查命令

Nuxt 5 目前仍在开发中,官方 Migrating to Nuxt 5 页面会随进展变化。下面记的是那些不报错、构建能通过、页面能打开,但代码路径已经变了的默认值改动,以官方 upgrade 文档为准。

先对齐运行时前置条件

jiti 不再被打包,nuxt.config、modules/、layer config 改为运行时加载,Node 需要 22.22 或 24.11 以上,TypeScript 类型剥离默认开启。运行时不再猜扩展名,也不会编译会产出代码的 TS 语法(enum、namespace、参数属性这类)。配置文件里带这类写法的要先拆掉。

① Options API 被编译出客户端包

Vue Options API 会被编译出客户端包以减小体积,存量 Options API 组件在客户端会失效。这条最容易漏,因为 SSR 首屏看起来完全正常,只有交互时才暴露。

grep -rln "export default {" --include=*.vue app/ | xargs grep -l "data()\|methods:\|computed:"

建议改写成 ``;过渡期可按目录在配置里保留旧行为。

② 路由默认区分大小写

router.options.sensitive 默认 true,/About 不再匹配 pages/about.vue。更麻烦的是它只能从 nuxt.config 读取——服务端匹配 route rules 用的是同一份设置,写在 app/router.options.ts 里会直接构建失败。

grep -rn "router.options" --include=*.ts .
grep -rn "navigateTo('/[A-Z]\|to=\"/[A-Z]\|href=\"/[A-Z]" --include=*.vue app/

链接统一小写,或显式在 nuxt.config 里设 sensitive: false。

③ server/utils/ 只有顶层自动导入

子目录不再自动导入,server/utils/db/helper.ts 这类会变成未定义。服务端自动导入整体也收紧了,helper 要从 nuxt/server 显式导入:defineEventHandler、createError、getQuery、readBody、cookie 与 header 助手、sendRedirect、getRouteRules、useRuntimeConfig。

find server/utils -mindepth 2 -type f
grep -rn "from 'nitropack'" --include=*.ts .

nitropack 包改名为 nitro,导入路径全变,顺手一起换掉。

④ clearNuxtState 重置为初始值

不再是 undefined。原来靠 if (state.x === undefined) 判断「未加载」的逻辑会一直走已加载分支,且不报错。

grep -rn "clearNuxtState" --include=*.ts --include=*.vue .

改成显式的 loaded 标记,或判断初始值本身。

⑤ 顶层 await navigateTo() 之后不再执行

setup() 里 await 一个成功的 navigateTo() 后,后续代码不再执行。原来「跳转后顺手清理状态 / 补一条埋点」的写法会被静默丢掉。

grep -rn "await navigateTo" --include=*.vue --include=*.ts .

把清理逻辑挪到 navigateTo 之前,或去掉 await、用返回值判断。

⑥ 错误响应格式不再看 Accept 头

页面错误固定返回错误页,server route 错误固定返回 JSON,与请求头无关。原先靠 Accept 头决定拿 HTML 还是 JSON 的调用方要改。同时 experimental.parseErrorData 强制开启,error.data 到达错误页时不再被字符串化,前端的解析代码也要跟着调。

⑦ useServerHead 系列不再自动导入

useServerHead、useServerHeadSafe、useServerSeoMeta 都要显式导入,unhead.legacy 被忽略。

grep -rn "useServerHead\|useServerSeoMeta" --include=*.vue --include=*.ts .

顺带核对一遍依赖 unhead.legacy 的 SEO 旧配置。

⑧ autoprefixer 与 cssnano 不再默认安装配置

原本自动带上的 PostCSS 处理没有了,前缀和产物压缩都会变。需要就手动安装并写进 PostCSS 配置。

grep -rn "autoprefixer\|cssnano" package.json postcss.config.* nuxt.config.*

结构性改动:Nitro v3 与 Vite 8

这两块不属于「静默出错」,但决定了迁移工作量。Nitro v3 基于 h3 v2 与 srvx,兼容层保留了未迁移的服务端代码,服务端工具统一从 nuxt/server 导入。Vite 8 用 Rolldown 取代 esbuild 与 Rollup:vite.esbuild、vite.optimizeDeps.esbuildOptions 弃用,换 vite.oxc 与 vite.optimizeDeps.rolldownOptions;build.rollupOptions 弃用,换 build.rolldownOptions;CommonJS interop 行为也有变化。可以先在 Nuxt 4 项目里把 "vite": "^8.3.0" 提上去试兼容,插件迁移单独开分支。

Vite Environment API 侧:extendViteConfig() 的 server/client 选项弃用;用 addVitePlugin() 且只针对单一环境(server:false 或 client:false)注册的插件,其 config 与 configResolved 钩子不再被调用;vite:extendConfig 与 vite:configResolved 现在作用于共享配置。按环境拆插件的逻辑要重过一遍。

上面几组 grep 建议直接塞进 CI,升级前后各跑一次对比结果。

复制全文 生成海报 Nuxt Vue 前端迁移 Node.js

推荐文章

程序员茄子在线接单