事情要从上周改叨叨那条”开始折腾 Nuxt”的时候说起。本以为写完那条就能慢慢把博客搬过去,结果一脚踩进去,到现在还没爬出来。
Vue 不熟这件事
首先要承认,我对 Vue 的接触大概停留在两年前写过几个小 demo 的水平。ref、reactive、computed 这些概念知道,但 Nuxt 那一套组合式 API + 自动导入 + 文件路由叠起来,每次写都要回头查文档。
最难受的是写法相似但语义不同。比如 defineProps 看着像 Astro.props,但响应式是默认开启的,于是我在父组件里改了 prop,子组件死活不更新,debug 了半小时才发现是要用 computed 包一层。
样式一迁移就崩
Astro 的 <style> 是 scoped 的,类名会加 hash;Nuxt 3 的 <style scoped> 行为类似,但默认注入的顺序和层叠规则不一样。
于是我看到的现象是:
- 同样的类名,在 Astro 里层级正确,到 Nuxt 里被全局 CSS 覆盖
- 字号、间距看起来”差不多”,但排版明显松紧不一致
- 媒体查询断点对了,可视宽度却错位几像素
更离谱的是毛玻璃(backdrop-filter),在 Astro 里一切正常,到 Nuxt 里要加 position: relative 和一个空 z-index 层才肯渲染——查了 issue 才确认是 SSR 注水顺序的锅。
400 / 500 错误连番来
getCollection 换成 Nuxt Content 之后,第一次跑 pnpm dev 报了一个 500,错误信息只有一句 Cannot read properties of undefined。翻了两小时日志,发现是 defineCollection 里漏了 source: 'log',content 根本没被注册。
紧接着是 400。改完路径之后 useAsyncData 拉到的永远是 null,但接口本身在;最后定位到是 queryContent 的 where 条件字段名拼错——pubDate 写成 pubdate,由于 schema 没显式声明,没在校验阶段暴露,直接带病上线。
再后来是部署到 Cloudflare Pages 时,server bundle 体积超限,构建 500。这个我承认是图省事把整站打成了一个函数。
慢慢摸到的几个小经验
记下来给以后同样冲动的自己:
- 迁移前先把现有站点的 设计 token(颜色、字号、间距)抽成 CSS 变量,能省一半返工
- 路由别一下子全切,先搬一个最简单的页面打通
pages/+layouts/+app.vue三件套 useHead和useSeoMeta二选一,别混用,搜索引擎那边抓到的 og 标签会重复- 出错先看
/.nuxt/types生成的类型文件,比看 dev server 日志直观 - 写
defineProps时多加withDefaults,默认值在 SSR 注水阶段能救命
说真的,比想象中恶心多了
写完上面那段经验时,以为事情差不多摸到门了,结果这两天又开始反复”撞墙”。越用越觉得,Nuxt 不是一个”写起来爽”的框架,而是一个要求你时刻保持敬畏的框架。
最让人崩溃的,是它那一套”看起来省心、实际上埋雷”的自动导入。
- 在
.vue文件里随手写一个useFoo(),没人告诉你它从哪来 - 想跳转到定义?不好意思,这个函数是构建时合成的,编辑器只能给你一个空泛的
unknown - 团队来了新人,排查 bug 时第一句话总是:“这个
useXxx哪儿的?”
更绝的是各种同名 API:
$fetch/useFetch/useAsyncData/useFetch的 server 版……四个 API 长得像,用法微妙地不一样,记错一个就 SSR 报Cannot read properties of undefineduseState是全局的,但只在客户端持久化;想跨请求共享,请再引入 PiniadefinePageMeta里能写middleware、能写layout、能写validate、还能写keepalive——字段多了之后没人记得每个键是干嘛的
还有 hydration 不匹配。生产环境第一次构建跑得好好的,改了一行 prop 之后页面”抖”了一下,控制台报了一句 Hydration node mismatch,错误位置指向第 47 行的某个 div。点过去一看,那是个空 div,两边的内容根本是一致的——只是 SSR 渲染顺序和 CSR 渲染顺序差了几毫秒。
最让人想骂街的是 dev server 的缓存:
- 改了
nuxt.config.ts里一个 plugin 的顺序,刷新页面没反应 - 改了
app.vue里的全局样式,刷新页面还是旧的 pnpm dev重启一次,三十秒过去了,你盯着黑屏发呆
写 Astro 时从来没这种感觉——Astro 的 dev server 启动快、改了就变、报错的位置很准。Nuxt 不是不行,是它把”约定”做得很厚,厚度上来之后,bug 也跟着厚。
暂时停一停
这周末决定先回到 Astro 继续更叨叨和随笔,Nuxt 的分支留着慢慢迭代。
不为别的——只是想让自己写得动。折腾工具的快乐不该盖过写东西本身。留个尾巴,等哪天摸熟了,再回来交一份完整的迁移笔记。