Nuxt 3 SSR 在 SEO 和首屏性能上优势明显,但也带来了 hydration 匹配的挑战。本文详解数据获取策略、分页缓存和三个实际踩坑案例。
Nuxt 3 SSR 实战
本博客前端使用 Nuxt 3 的服务端渲染模式。SSR 的最大收益是 SEO——搜索引擎直接拿到完整 HTML,无需执行 JavaScript。
数据获取策略
Nuxt 3 提供了三个数据获取 composable:
<script setup>
// 1. useAsyncData — SSR 阶段执行,数据嵌入 HTML
const { data } = await useAsyncData('home', () =>
get('/api/articles', { page: page.value, size: 24 }),
{ watch: [page] }
)
// 2. useLazyAsyncData — 客户端执行,不阻塞页面渲染
const { data: siteInfo } = useLazyAsyncData('site-info', () =>
get('/api/site').catch(() => ({}))
)
// 3. useFetch — useAsyncData 的封装,自动处理 baseURL
const { data } = await useFetch('/api/articles')
</script>
区分 SSR 和客户端数据的标准:
- 首屏必须展示的内容 →
useAsyncData(文章列表、文章详情) - 非关键的内容 →
useLazyAsyncData(站点信息、作者资料) - 用户操作触发的内容 → 客户端手动 fetch(评论提交、搜索)
分页与数据刷新
useAsyncData 默认缓存 key 是固定的,当页面查询参数变化时不会自动刷新。解决办法是使用 watch 选项:
const { data } = await useAsyncData(
'home',
() => get('/api/articles', { page: page.value, size: 24 }),
{ watch: [page] }
)
watch: [page] 让 Nuxt 监听 page 这个 reactive ref,变化时自动重新执行查询函数并更新 UI。
组件自动导入
Nuxt 3 支持 components/ 目录下的组件自动导入,无需手动 import:
// nuxt.config.ts
components: {
dirs: [
'~/components/base', // 基础组件(GlassCard, Pagination...)
'~/components/blog', // 业务组件(ArticleCard, CommentSection...)
'~/components/search',
'~/components/admin',
],
},
模板中直接用 <GlassCard> 即可,Nuxt 按目录优先级查找。如果多个目录有同名组件,前面的目录优先。
Hydration 踩坑
Vue 3 的 hydration 机制要求 SSR 输出和客户端首次渲染的 DOM 完全一致。本博客遇到过的三个典型问题:
问题 1:`` 标签差异
症状:Hydration children mismatch on <a>,导航栏中的 NuxtLink 报错。
根因:Vue Router 在客户端会 patch 所有带 href 的 <a> 元素(拦截导航、绑定事件),导致 children 数量不一致。哪怕用了原生 <a :href="..."> 也是如此。
解决:用 <div @click="router.push()"> 替代 <a>。
问题 2:动态 class/attribute 不一致
症状:空的 style="" 属性在 SSR 输出中不存在,但客户端渲染时会添加。
解决:把动态绑定移到父容器,子组件保持纯静态 HTML。
问题 3:条件渲染的 `v-if`
症状:v-if 在 SSR 和客户端判断结果不同(如 sessionStorage 检查)。
解决:将客户端初始化逻辑放到 onMounted,SSR 阶段统一渲染为 false。
开发工具链
开发模式同时启动三个进程:
# 终端 1:后端 API
cd backend && uvicorn main:app --reload --port 8001
# 终端 2:前端 dev server
cd frontend && npm run dev # 端口 3000
# 前端通过 Vite proxy 代理 API 请求到 8001
start.bat 脚本一键同时启动前后端。
SEO 配置
- Nuxt SSR 直接输出 HTML,爬虫可完整抓取
public/robots.txt允许所有爬虫/api/sitemap.xml动态生成站点地图- URL 使用 slug 而非 id(
/p/redis-cache优于/p/42) - 已提交 Google Search Console + Bing Webmaster Tools
评论
暂无评论,来写第一条吧
