文章目录前言一、三种渲染模式1.1 对比1.2 CSR 流程1.3 SSR 流程1.4 SSG 流程二、SSR 基本架构2.1 同构应用2.2 服务端渲染示例2.3 返回给浏览器的 HTML 结构三、Hydration 客户端激活3.1 是什么3.2 Hydration 不匹配3.3 避免不匹配四、数据预取与状态同步4.1 问题4.2 脱水与注水五、Streaming SSRVue 35.1 传统 SSR 的问题5.2 流式渲染六、SSR 开发注意事项6.1 生命周期6.2 浏览器 API6.3 第三方库6.4 Teleport 与 SSR七、Nuxt 简介7.1 为什么用 Nuxt7.2 Nuxt 3 vs Nuxt 2八、何时选 SSR九、面试聚焦9.1 onMounted 只在客户端执行9.2 Hydration 不匹配会怎样9.3 SSR 中能用 window/document 吗9.4 SSR 和 SSG 区别十、易混淆点十一、思考与练习总结前言SSRServer-Side Rendering在服务端将 Vue 组件渲染成 HTML 再发给浏览器可提升首屏速度与 SEO。本篇会讲清楚SSR、CSR、SSG 的区别渲染流程与 Hydration 激活数据预取与状态脱水/注水SSR 开发注意事项与 Nuxt 简介一、三种渲染模式1.1 对比模式首屏 HTML渲染位置SEO适用CSR空壳 JS浏览器差中后台、强交互SSR完整 HTML服务器每次请求好内容站、电商详情SSG完整 HTML构建时预渲染好博客、文档、营销页1.2 CSR 流程浏览器请求 → 返回 index.html几乎为空 ↓ 下载 JS → 执行 Vue → 请求 API → 渲染页面首屏白屏时间长爬虫难以抓取动态内容。1.3 SSR 流程浏览器请求 → 服务器执行 Vue → 生成 HTML 嵌入状态 ↓ 返回完整 HTML用户立刻看到内容 ↓ 下载 JS → Hydration 激活 → 变为可交互 SPA1.4 SSG 流程构建时 → 对每个路由预渲染静态 HTML ↓ 部署到 CDN → 请求直接返回静态文件内容不频繁变化时SSG 比 SSR 服务器压力更小。二、SSR 基本架构2.1 同构应用同一套 Vue 代码在服务端和客户端各运行一次┌─────────────┐ │ Vue 组件 │ └──────┬──────┘ │ ┌──────────┴──────────┐ ↓ ↓ 服务端 render 客户端 hydrate renderToString createApp mount ↓ ↓ HTML 字符串 可交互应用2.2 服务端渲染示例// server.jsimport{createSSRApp}fromvueimport{renderToString}fromvue/server-rendererimportAppfrom./App.vueexportasyncfunctionrender(url){constappcreateSSRApp(App)consthtmlawaitrenderToString(app)returnhtml}// entry-client.js客户端import{createSSRApp}fromvueimportAppfrom./App.vueconstappcreateSSRApp(App)app.mount(#app)// Hydration2.3 返回给浏览器的 HTML 结构!DOCTYPEhtmlhtmlbodydividapp!-- 服务端渲染的 HTML --/divscriptwindow.__INITIAL_STATE__{...}/scriptscriptsrc/client.js/script/body/html三、Hydration 客户端激活3.1 是什么Hydration水合是客户端 Vue接管服务端 HTML 的过程绑定事件、恢复响应式使静态 HTML 变成可交互应用。服务端 HTML静态无事件 ↓ 客户端 JS 加载 Vue 对比 VNode 与服务端 DOM ↓ 匹配成功 绑定事件监听、挂载组件实例 ↓ 完整 SPA3.2 Hydration 不匹配服务端与客户端渲染结果不一致时会报警告[Vue warn]: Hydration node mismatch常见原因服务端与客户端数据不同时间戳、random、locale使用了window/document导致两端 HTML 不同浏览器插件修改 DOM无效 HTML 结构如p内嵌div后果控制台警告可能导致事件绑定失败、样式错乱。解决保证同一份数据、同一份模板两端 render 结果一致动态内容放ClientOnly或onMounted。3.3 避免不匹配script setup import { ref, onMounted } from vue // ❌ 服务端和客户端结果不同 const time ref(new Date().toLocaleString()) // ✅ 仅在客户端设置 const time ref() onMounted(() { time.value new Date().toLocaleString() }) /script四、数据预取与状态同步4.1 问题服务端 render 时需要数据客户端 Hydration 后也需要相同数据否则不匹配。4.2 脱水与注水服务端 1. 预取 API 数据 2. render 进 HTML 3. 序列化 state → 嵌入 __INITIAL_STATE__ 客户端 1. 读取 __INITIAL_STATE__ 2. 注入 Pinia / Vuex 3. Hydration与服务端同一状态// 服务端constpiniacreatePinia()constappcreateSSRApp(App).use(pinia)awaitrouter.push(url)awaitprefetchData()// 路由级数据预取consthtmlawaitrenderToString(app)conststateJSON.stringify(pinia.state.value)// 嵌入模板scriptwindow.__INITIAL_STATE__${state}/script// 客户端constpiniacreatePinia()if(window.__INITIAL_STATE__){pinia.state.valuewindow.__INITIAL_STATE__}app.use(pinia).mount(#app)每个请求需独立 Pinia 实例避免用户间状态污染。五、Streaming SSRVue 35.1 传统 SSR 的问题renderToString需等整页数据就绪才返回 HTML慢接口拖慢 TTFB。5.2 流式渲染import{renderToNodeStream}fromvue/server-rendererconststreamrenderToNodeStream(app)stream.pipe(response)边渲染边发送 HTML浏览器可更早解析和展示先就绪的部分改善首字节时间。六、SSR 开发注意事项6.1 生命周期钩子服务端客户端setup同步代码✅✅onBeforeMount✅✅onMounted❌✅onServerPrefetch✅❌面试常考onMounted只在客户端执行。服务端专用数据预取用onServerPrefetch。import{onServerPrefetch,onMounted}fromvueonServerPrefetch(async(){awaitstore.fetchList()// 仅服务端render 前完成})onMounted((){initChart()// 仅客户端可访问 DOM})6.2 浏览器 API// ❌ SSR 中会报错constwidthwindow.innerWidth document.titlexxx// ✅ 环境判断if(import.meta.env.SSR){// 服务端逻辑}else{// 客户端逻辑}// ✅ 或放 onMountedonMounted((){document.titlexxx})6.3 第三方库仅支持浏览器的库ECharts、地图 SDK应在onMounted或ClientOnly中加载避免服务端执行。6.4 Teleport 与 SSRTeleport 在 SSR 时默认原位渲染客户端 hydration 后才传送到目标位置可能短暂闪烁详见《Teleport 传送门》。七、Nuxt 简介7.1 为什么用 Nuxt手写 SSR 需处理路由、数据预取、代码分割、Hydration 配置复杂度高。Nuxt 是 Vue 官方 SSR 框架开箱即用。7.2 Nuxt 3 vs Nuxt 2对比项Nuxt 2Nuxt 3Vue 版本Vue 2Vue 3API 风格Options 为主Composition API引擎传统 Node 服务Nitro边缘、Serverless 友好渲染SSR / SPASSR / SSG / Hybrid数据获取asyncData/fetchuseFetch/useAsyncData!-- Nuxt 3 页面 -- script setup const { data } await useFetch(/api/posts) /script template ul li v-forpost in data :keypost.id{{ post.title }}/li /ul /templateuseFetch在服务端预取自动脱水/注水到客户端。八、何时选 SSR选 SSR选 CSR选 SSGSEO 重要纯后台系统博客、文档首屏要快登录后应用内容更新不频繁社交分享预览实时协作工具营销落地页SSR 代价服务器成本、开发复杂度、需注意 Hydration 与环境差异。九、面试聚焦9.1 onMounted 只在客户端执行服务端没有 DOMmounted 类钩子仅客户端运行服务端数据用onServerPrefetch。9.2 Hydration 不匹配会怎样控制台警告可能导致事件未绑定、交互异常。需保证两端 render 一致。9.3 SSR 中能用 window/document 吗不能直接在 setup 中用会服务端报错或无定义。用import.meta.env.SSR判断或onMounted。9.4 SSR 和 SSG 区别SSR 每次请求在服务器渲染SSG 构建时生成静态 HTML部署后无需 Node 服务。十、易混淆点SSR ≠ 不需要 JSHydration 后仍是 SPAJS 必下载。SSR ≠ SSG动态 SSR vs 构建时静态化。setup 两端都跑不是只有客户端。状态必须同步脱水/注水失败 → Hydration mismatch。每个请求独立 storeSSR 不能共享全局单例状态。十一、思考与练习1.SSR 的核心流程解析服务端 renderToString 生成 HTML → 返回浏览器 → 客户端加载 JS → Hydration 激活。2.什么是 Hydration解析客户端 Vue 接管服务端 HTML绑定事件、恢复响应式使页面可交互。3.为什么 SSR 里不能直接用 window解析Node 服务端无 window执行会报错需环境判断或 onMounted。4.INITIAL_STATE的作用解析服务端序列化状态嵌入 HTML客户端读取后注入 store保证 Hydration 数据一致。5.什么时候用 Nuxt 而不是手写 SSR解析需要完整 SSR 工程路由、数据、构建、部署时Nuxt 降低同构开发成本。总结SSR服务端渲染 HTML提升首屏与 SEO客户端 Hydration 激活CSR / SSG纯客户端 vs 构建时静态化按场景选型Hydration两端 HTML 须一致否则警告与交互异常数据预取 脱水/注水__INITIAL_STATE__同步状态注意onMounted 仅客户端、禁用 window/document、每请求独立 storeNuxt 3Vue 3 NitrouseFetch 等简化 SSR 开发