Appearance
SSR / SSG 与元框架:全栈化与同构
最后更新:2026-08-19
本主题要回答的问题
- SPA 已经把渲染搬进浏览器了,为什么又要"回到"服务端渲染?
- SSR、SSG、ISR 三者的区别到底是什么?什么时候选谁?
- "元框架"(Next.js/Nuxt)在框架之上又加了什么?为什么需要?
一、问题:SPA 的两道硬伤
SPA 把渲染搬到浏览器后,代价同样明显:
| SPA 硬伤 | 表现 |
|---|---|
| 首屏慢 | 浏览器要先下载并执行完整个 JS bundle,<div id="root"></div> 才被"点亮" |
| SEO 差 | 爬虫(尤其无头爬虫)执行 JS 前看到的是空壳,关键词抓不到 |
于是"在服务器上先把 HTML 渲染出来"的旧思路,以新形式回归——这就是同构(Isomorphic):同一套组件代码,既能在服务端渲染成 HTML,又能在浏览器端水合(hydration)成交互应用。
二、三种形态:SSR / SSG / ISR
| 形态 | 全称 | 渲染时机 | 特点 | 适合场景 |
|---|---|---|---|---|
| SSR | Server-Side Rendering | 每次请求时在服务器渲染 | 内容永远最新,但每次请求都要算 | 电商、社交动态页 |
| SSG | Static Site Generation | 构建时渲染成静态 HTML | 最快最省,但内容变化要重新构建 | 博客、文档站 |
| ISR | Incremental Static Regeneration | 构建时 + 定时/按需重建 | SSG + 自动失效重建 | 内容半动态(新闻列表) |

三、水合(Hydration):SSR 的"下半场"
SSR 出的 HTML 只是"静态画面",要变成可交互应用,浏览器还需执行同一套 JS 并把事件绑回(水合)DOM:
| 阶段 | 谁在做 | 产出 |
|---|---|---|
| 服务端渲染 | Node 服务器 | 完整 HTML(首屏立即可见) |
| 客户端加载 JS | 浏览器 | 加载组件代码 |
| 水合 | 浏览器 | 事件绑定、状态接管,页面"活"过来 |
代价:同构代码要在双端运行,于是出现了"水合不匹配"(服务端与客户端渲染结果不同导致报错)等问题;下一代优化方向是流式渲染、部分水合、岛架构(Islands,Astro 的代表作——只对交互组件水合,静态部分直接发 HTML)。
四、元框架:约定优于配置
React/Vue 本身不解决"路由、SSR、数据获取、SEO"——于是**元框架(meta-framework)**在框架之上提供完整应用脚手架:
| 元框架 | 底层框架 | 特点 |
|---|---|---|
| Next.js | React | 行业事实标准:App Router、RSC(React Server Components) |
| Nuxt | Vue | Vue 全家桶集成,Nitro 服务端引擎 |
| SvelteKit | Svelte | 编译期优化,体积最小 |
| Astro | 任意 | "内容岛"架构,默认零 JS 输出 |

元框架 = 框架 + 路由 + SSR/SSG 开关 + 数据获取 + 部署适配,让开发者用配置/约定而非手写胶水代码,来选择每个页面走 SSR 还是 SSG。
五、VitePress:SSG 家族的一员
文档站是最典型的 SSG 场景:内容在构建期已知、几乎不需要服务端逻辑。VitePress(本站所用)正是"基于 Vite 的文档 SSG"——构建期把 Markdown 编译成静态 HTML,部署后零服务器渲染成本。详见VitePress 专篇。
一句话总结
SSR/SSG 不是"回到过去",而是把渲染时机当成可选项:SSR 把渲染放在请求期(内容新),SSG 放在构建期(速度快),ISR 折中(构建 + 按需重建);元框架则把这一套选择集成进框架约定里——前端由此进入"同一套代码,双端渲染,按页选时机"的全栈时代。