Skip to main content

页面渲染模式

这篇文章本来是为补齐「技术选型」章节而写的,但写着写着发现它本身就是选型决策里权重最大的一环——一旦定了渲染模式,框架、部署、SEO 策略基本就锁死了。所以单独拎出来讲。

一、为什么先讲渲染模式而不是框架

很多团队做技术选型时,第一反应是「选 React 还是 Vue」。但这只是工具,真正的"地基决策"是页面在什么时机、用什么方式生成 HTML——这就是渲染模式(Rendering Mode / Rendering Strategy)。

不同的渲染模式决定了:

  • 首屏快不快(FCP / LCP / TTFB 三大指标)
  • SEO 友不友好(爬虫能不能拿到内容)
  • 部署成本(需不需要 Node 运行时)
  • 服务端压力(峰值时打向 Node 的 QPS)
  • 交互体验(页面是否有一瞬白屏、是否有 hydration mismatch 闪烁)

下面把主流的 6 种渲染模式一次性讲清。

二、6 种主流渲染模式

1. CSR(Client-Side Rendering,客户端渲染)

核心特点:服务端只返回一个几乎空白的 HTML 壳 + 一个 JS bundle,所有页面内容在浏览器里跑 JS 生成。

执行时机

请求 ──→ CDN/Nginx 返回空 HTML

浏览器解析 HTML,遇到 <script> 标签

下载、解析、执行 JS bundle(React/Vue runtime + 业务代码 + 数据请求)

JS 在浏览器里 createRoot + render,组件渲染出真实 DOM

页面可见

典型代表:Vite + React/Vue 的纯 SPA 模板(create-react-appcreate-vueVite 默认模板)

优点

  • 部署最简单,纯静态文件,任何静态服务器都能 serve(Nginx、CDN、GitHub Pages)
  • 服务端压力小(HTML 是固定的,缓存到极致)
  • 前后端分离彻底,前端可以独立部署

缺点

  • 首屏白屏时间长:JS bundle 越大、网速越慢,白屏越久。3G 环境下可能 3~5 秒
  • SEO 极差:爬虫拿到的只有 <div id="root"></div>,看不到任何内容(Googlebot 虽能跑 JS 但要等,百度爬虫基本抓不到
  • 数据请求串行化:HTML → JS → API → 渲染,至少 3 个串行网络请求

适用场景:内部后台、管理系统、看板类工具、对 SEO 和首屏速度无要求的应用。


1.5 容易混淆的概念:MPA vs SPA

在聊下面 5 种渲染模式之前,先把两个常被混用、但本质完全不同的概念讲清楚:MPA(多页应用)SPA(单页应用)

维度MPA(Multi-Page Application)SPA(Single-Page Application)
HTML 数量每个路由对应一个独立的 .html 文件整个应用只有 1 个 index.html
页面切换每次都重新加载整页(浏览器地址栏会有真实跳转)不重新加载 HTML,前端路由(History API / Hash)切换组件
首屏渲染服务端直接吐完整 HTML(一般是 MPA + SSR)浏览器跑 JS 渲染(SPA + CSR)
典型代表传统 PHP/Java 网站、jQuery 时代的多页应用、Next.js 用 next/link 之前Vite + React 默认模板、Vue Router、React Router
优点简单直接、SEO 天然友好、各页面解耦切换页面无白屏、用户体验"类原生"
缺点每次切换都重新加载 HTML/JS,体验割裂首屏白屏、SEO 差、对前端路由处理要求高

关键澄清

  • SPA 不是渲染模式——它是架构形态。判断标准是"页面切换时刷不刷新整个 HTML"
  • CSR/SSG/SSR 是渲染模式——它们判断的是"首屏 HTML 是什么时候、怎么生成的"
  • 二者正交:可以 SPA + SSR(如 Next.js 用了 next/link,首屏 SSR,后续走 SPA 路由),可以 MPA + CSR(极少见,不推荐),可以 SPA + SSG(如 Gatsby,或 Next.js 的纯静态导出 output: export

为什么现代框架几乎全是 SPA 形态

因为 SPA 切换页面的体验远胜 MPA(没有白屏、保留 state、动画连贯)。所以即便 Next.js/Astro 默认是 SSG/SSR(首屏吐完整 HTML),它们也都提供了前端路由(next/link<a> + View Transitions)让用户感觉上是个 SPA。

反直觉的细节

  • 传统 jQuery 时代的多页应用 → MPA + 服务端渲染(连 SSR 都不算,就是 PHP 直接 echo HTML)
  • Vite + React 纯前端模板 → SPA + CSR
  • Next.js 用了 next/linkSPA 体验 + SSG/SSR 渲染
  • 一个 SSG 静态站加了 View Transitions 动画 → 严格说还是 MPA(多个 HTML),但体感是 SPA

记住一句话:SPA 看路由刷不刷新整页,渲染模式看首屏 HTML 怎么生成——两个维度,互不干扰


2. SSR(Server-Side Rendering,服务端渲染)

核心特点:每次请求时,Node 服务端实时执行组件代码、生成完整 HTML 返回给浏览器,浏览器拿到 HTML 后下载 JS 完成水合(hydration)。

执行时机

请求 ──→ Node 服务端执行 React/Vue 组件代码

调用 API/DB 拿到数据,渲染成 HTML 字符串

返回完整 HTML(带内容)

浏览器立即看到内容(FCP 优秀)

下载 JS bundle 并执行

React/Vue 在客户端「水合」——接管 DOM,绑事件,启动交互

典型代表:Next.js(output: 'server'getServerSideProps)、Nuxt 3(默认)、Remix、SvelteKit(默认)、Express + React 手动实现

优点

  • 首屏极快:浏览器拿到的就是带内容的 HTML,FCP/LCP 都很好
  • SEO 友好:HTML 直接带内容,爬虫直接抓
  • 数据始终最新:每次请求都重渲染(适合强实时场景,如股票、库存、用户个性化内容)

缺点

  • 服务端压力大:每个请求都要跑一次组件代码、查一次 DB。QPS 高时必须做缓存、负载均衡、扩 Node 实例
  • TTFB 受影响:服务端渲染本身有几十~几百 ms 耗时,加上网络 RTT,首字节时间比纯静态差
  • 部署成本高:必须常驻 Node 进程,不能像 SSG 那样丢 CDN
  • Hydration mismatch 闪烁:服务端渲染和客户端首次渲染结果不一致时(比如用了 Date.now()Math.random()window),控制台会报错并强制重渲染
  • Node 冷启动:Serverless 部署时冷启动可能 200~500 ms

适用场景:电商商品详情、新闻门户、用户个性化首页、强 SEO 需求 + 实时数据的应用。


3. SSG(Static Site Generation,静态站点生成)

核心特点构建时(build time)把所有页面一次性渲染成静态 HTML 文件,部署后用户访问的就是这些预先生成的 .html部署时不再有任何 Node 运行时

执行时机

pnpm build

[Astro/Next/Nuxt 编译器]

遍历所有路由,对每个页面跑一次组件代码,生成 .html 文件

产物:dist/ 下有一堆 .html + JS + CSS

部署到 Nginx/CDN/GitHub Pages

用户请求 ──→ 直接返回预先生成的 .html(毫秒级)

典型代表:Astro(默认 SSG)、Next.js(output: 'static'getStaticProps)、Nuxt 3(nuxt generate)、Hugo、Jekyll、11ty、VitePress

优点

  • 首屏极快 + 部署极简:纯静态文件,CDN 全缓存,QPS 扛得住任何量级(淘宝双十一首页是 SSG 的经典案例)
  • SEO 极佳:HTML 完整带内容
  • 托管便宜:GitHub Pages、Vercel、Netlify、腾讯云 COS、阿里云 OSS 都能直接 serve,几乎零成本
  • 安全性高:没有 Node 运行时,攻击面小

缺点

  • 构建时间随页面数线性增长:1 万个页面要构建很久。Next.js 有 ISR 缓解,Astro/Hugo 是"全量重 build"模式
  • 内容更新延迟:必须重新 build + 重新部署才能更新,对秒级实时数据不友好
  • 不适合强个性化:所有用户看到的 HTML 一样,登录态、A/B 测试、地域分发都得靠客户端 JS 二次拉取

适用场景:博客、文档站、营销页、官网、ShaderPad 这种"内容为主 + 轻交互"的工具站。


4. ISR(Incremental Static Regeneration,增量静态再生)

核心特点:SSG + 按需重新生成。首次请求时缓存静态 HTML,后续请求直接返回缓存;缓存过期或主动 revalidate 时,下一个请求触发后台重新生成。

执行时机

请求 /blog/post-1

[CDN 缓存有吗?]──是──→ 直接返回缓存(毫秒级)
↓ 否
[静态文件存在吗?]──是──→ 返回静态文件 + 后台异步重新生成
↓ 否
Node 服务端实时渲染 HTML ──→ 返回 + 写缓存

典型代表:Next.js(revalidate: 60res.revalidate('/path'))、Nuxt 3(routeRules: { isr: 60 }

优点

  • 兼具 SSG 的速度 + SSR 的实时性:99% 的请求走静态缓存,1% 的请求触发重新生成
  • 构建时间不爆炸:1 万个页面也不用一次 build 完,按需生成

缺点

  • 框架支持有限:Next.js 最成熟,Nuxt 3 刚支持,Astro/Hugo 没有
  • 部署需要 Node 运行时(虽然大部分请求不走 Node):所以不能纯 CDN 部署
  • 缓存一致性略复杂:需要正确配置 revalidate 时间和 on-demand revalidation

适用场景:电商商品列表(价格/库存偶尔变)、新闻门户(每小时更新)、大型内容站。


5. RSC(React Server Components,React 服务端组件)

核心特点:React 19 引入的新模式,组件分两种

  • Server Component:在服务端跑,永远不会发到浏览器。可以直接查 DB、读文件、调用内部 API,不暴露任何代码逻辑
  • Client Component:传统 React 组件,必须在浏览器跑('use client' 指令)

执行时机

请求 ──→ 服务端渲染 RSC 树

[遇到 Server Component] → 在 Node 端跑,组装 UI 树

[遇到 Client Component] → 在 UI 树中插入占位符 + 引用

返回特殊格式的 RSC payload(不是 HTML 也不是 JSON,是 React 自己的流式协议)

浏览器解析 payload → 渲染 Server Component 部分 + 拉取 Client Component 代码

典型代表:Next.js 13+ App Router(默认全部是 RSC,传统组件需要 'use client')、Waku、Parcel

优点

  • 更小的客户端 bundle:Server Component 的代码完全不下发,库、工具函数、数据获取逻辑全部留在服务端
  • 直接访问后端资源:不用单独写 API,组件里直接 await db.query(...)
  • 天然适合数据流:服务端组件可以 await 任意数据,子组件自动 stream 出来

缺点

  • 学习曲线陡:心智模型和传统 React 完全不一样,'use client' 边界要谨慎处理
  • 生态还在适应:很多第三方库(特别是 state 管理、动画库)需要 'use client' 包装
  • 调试和报错相对复杂:服务端组件报错时控制台在 Node 端,浏览器端看到的是"缩小版"错误信息

适用场景:数据密集型应用(Dashboard、Admin)、需要服务端直接访问数据但又要 React 组件树的应用。


6. Astro Islands(群岛架构 / 部分水合)

核心特点默认全站 SSG(零客户端 JS),但允许在静态海面中插入孤岛(Interactive Islands),孤岛可以独立选择水合时机。每个孤岛都是独立的微型 SPA

执行时机

pnpm build

[Astro 编译器]

所有不带 client:* 指令的组件 → 渲染为纯 HTML,JS 全部剥离

带 client:load / client:visible / client:only 等指令的组件 → 渲染为 <astro-island> 占位符,组件及其依赖打成独立 chunk

产物:HTML 极小(只 6~10KB),孤岛 chunk 按需加载

浏览器加载 → 首屏立即可见(FCP 极快)

调度器扫描 <astro-island> → 按指令策略 fetch 组件 chunk + 框架运行时

孤岛完成水合,与周围静态海面完全独立

5 种水合指令

指令触发时机适用场景
client:load页面加载立即 hydrate首屏关键交互(导航、登录框)
client:idle浏览器空闲时(requestIdleCallback非关键增强(评论区、推荐位)
client:visible元素进入视口(IntersectionObserver长页面底部的组件(折叠面板、视频)
client:media匹配媒体查询(如 (min-width: 768px)响应式组件(移动端/桌面端不同交互)
client:only跳过任何 SSR,只在客户端渲染强依赖浏览器 API 的(WebGL、Canvas、Audio)

典型代表:Astro(唯一原生支持)、SolidStart、Qwik City(resumability 思路类似)

优点

  • 首屏极致快:默认零 JS,HTML 极小
  • 按需加载颗粒度最细:可以精确到"页面里这个按钮要不要 JS"
  • 多框架混用:同一个页面里 React、Vue、Svelte 可以共存
  • 部署和 SSG 一样简单:纯静态文件,CDN 全缓存

缺点

  • 不适合强交互 SPA:像 Figma、Notion 这种"整个页面都是交互"的工具,Astro 反而是包袱——所有组件都成孤岛了,跨孤岛状态管理麻烦
  • 生态比 Next.js 小:很多 React 生态的库没做 Astro 适配

适用场景:博客、文档站、营销页、「主静态 + 局部重交互」的工具站(ShaderPad、Stripe Docs、Tailwind UI)。


三、6 种模式全景对比

模式渲染时机SEO首屏服务端压力部署复杂度适合场景
CSR浏览器❌ 差❌ 慢(白屏)✅ 几乎为零✅ 极简(纯静态)后台、内部工具
SSR请求时✅ 好✅ 快❌ 高(每请求渲染)❌ 需 Node 运行时电商、新闻、个性化
SSG构建时✅ 极佳✅ 极快✅ 几乎为零✅ 极简(纯静态)文档、博客、营销页
ISR构建时 + 按需再生✅ 好✅ 快🟡 低(仅失效时)🟡 需 Node 运行时大型内容站、电商列表
RSC请求时✅ 好✅ 快🟡 中(仅 RSC 部分)🟡 需 Node 运行时数据密集型应用
Astro Islands构建时 + 按需 hydrate✅ 极佳✅ 极快✅ 几乎为零✅ 极简(纯静态)文档+工具混搭站

一句话总结:CSR 是反 SEO 的纯前端;SSG/SSR 是 SEO 双雄;SSG 部署最便宜;ISR/RSC 是性能与动态的折中;Astro Islands 是「SSG 的极致」


四、每种模式对应的主流框架

模式代表框架默认渲染备注
CSRVite + React/Vue、create-react-app、create-vueCSR纯静态模板
SSRNext.js、Nuxt、Remix、SvelteKit、Express + React可选同一框架通常支持多种模式
SSGAstro(默认)、Hugo、Jekyll、VitePress、Next.js(output: 'static'SSGAstro 是 SSG 的事实标准
ISRNext.js、Nuxt 3SSG 基础上按需再生Next.js 的杀手锏
RSCNext.js 13+ App Router(默认 RSC)、WakuRSCNext.js 在 RSC 上一骑绝尘
Astro IslandsAstro群岛Astro 独此一家

重要观察:Next.js 是唯一同时支持 SSG / SSR / ISR / RSC 四种模式的全能框架。这也是它在前端选型中长期霸榜的原因——选 Next.js 等于"渲染模式可以以后再决定",前期试错成本低

但代价是 Next.js 的"全"也意味着"重"——同样的需求,如果一开始就明确是 SSG 场景,Astro 的产物会小一个数量级,部署也简单一个数量级


五、框架横向对比

下表对比的不是渲染模式本身(上面已经讲过),而是「同样想做 SSG/SSR/CSR 的项目,不同框架的差异」

框架底层语言默认模式多框架混用部署形态学习曲线适合项目
Next.jsReactSSR + RSC❌ 仅 React需 Node 运行时🟡 中等通用全栈、SEO 站
Nuxt 3VueSSR❌ 仅 Vue需 Node 运行时🟢 平缓Vue 团队全栈项目
RemixReactSSR❌ 仅 React需 Node 运行时🟡 中等强交互 Web App
Astro多框架SSG + 群岛✅ 任意纯静态🟢 最平缓文档/工具混搭站
SvelteKitSvelteSSR❌ 仅 Svelte需 Node 运行时🟢 平缓Svelte 粉丝、性能敏感站
GatsbyReactSSG❌ 仅 React纯静态🔴 陡(GraphQL 强绑定)已被 Astro 取代的方案
Vite + ReactReactCSR❌ 仅 React纯静态🟢 最简单后台、纯 SPA

几个关键判断点

  • 「必须多框架混用」 → 选 Astro(唯一选项)
  • 「团队只会 React」 → Next.js / Vite + React 二选一
  • 「强 SEO + 实时数据 + 团队是 React」 → Next.js(用 SSR 或 RSC)
  • 「内容为主 + 偶尔有重交互组件」 → Astro
  • 「整个页面都是重交互(Notion / Figma 类)」 → 推荐纯 CSR(Vite + React),这类项目不要用 Astro 这类群岛框架
  • 「内容站 + 1 万+ 页面 + 数据偶尔变」 → Next.js(用 ISR)

六、针对一个新项目怎么选?

决策树

新项目启动

├─ Q1: 需不需要 SEO?
│ │
│ ├─ ❌ 不需要(后台/工具/看板)
│ │ └─ → CSR(Vite + React/Vue)✅ 最简单
│ │
│ └─ ✅ 需要
│ │
│ ├─ Q2: 数据是强实时还是个大概就行?
│ │ │
│ │ ├─ 强实时(电商库存、股票、个性化)
│ │ │ └─ → SSR(Next.js / Nuxt)✅
│ │ │
│ │ └─ 偶尔更新(博客、文档、商品列表)
│ │ │
│ │ ├─ Q3: 页面数 & 团队偏好
│ │ │ │
│ │ │ ├─ 1 万+ 页面 + 团队是 React
│ │ │ │ └─ → ISR(Next.js)✅
│ │ │ │
│ │ │ ├─ 中小规模 + 团队任意
│ │ │ │ └─ → SSG(Astro / Hugo)✅
│ │ │ │
│ │ │ └─ 内容 + 重客户端工具(ShaderPad)
│ │ │ └─ → Astro Islands ✅
│ │ │
│ │ └─ Q3': 数据要从 DB 拉?
│ │ │
│ │ └─ 是 → RSC(Next.js App Router)✅
│ │
│ └─ Q2': 整站强交互(Notion/Figma 类)?
│ │
│ └─ 是 → Next.js / Remix(CSR 模式)✅

4 个典型场景的选型建议

场景 1:企业内部后台 / 管理系统

  • 渲染模式:CSR
  • 框架:Vite + React + Ant Design / Arco Design
  • 部署:纯静态文件 + Nginx
  • 理由:无 SEO 需求、整站都是交互、用户登录后使用、白屏几秒无所谓

场景 2:电商官网 / 资讯门户

  • 渲染模式:SSR + ISR 混合(首页/列表页用 ISR 缓存、详情页/个人中心用 SSR 实时)
  • 框架:Next.js 14+(App Router + RSC)
  • 部署:Vercel / 自建 K8s + Node 集群
  • 理由:SEO 核心 + 数据强实时 + 团队是 React

场景 3:技术文档站 / 个人博客

  • 渲染模式:SSG
  • 框架:Astro / VitePress / Docusaurus
  • 部署:GitHub Pages / Vercel / 腾讯云 COS 静态托管
  • 理由:内容更新频率低、对 SEO 极敏感、想要最便宜的部署

场景 4:在线工具站(ShaderPad / CodePen / Figma)

  • 渲染模式:Astro IslandsNext.js(CSR 模式)
  • 框架:Astro(如果文档 + 工具混搭)或 Vite + React(如果纯工具)
  • 部署:纯静态 + CDN
  • 理由:内容部分(介绍页/文档)需要 SEO + 加载速度,工具部分(编辑器/画布)是重客户端交互

几个反直觉的提醒

  • 不要为了"用 Next.js"而用 Next.js:如果需求就是 SSG 文档站,Next.js 的产物会比 Astro 大 5~10 倍、部署也比 Astro 复杂
  • 不要给后台加 SSR:白屏时间不会改善,反而引入了 Node 部署成本
  • 不要在 SSG 站点里大量使用 useEffect 二次拉数据:相当于把 SSG 退化成了 CSR
  • 先决定渲染模式,再选框架:顺序反了很容易后期想换模式时发现框架不支持

七、一句话总结

渲染模式是地基,框架是工具。地基没选好,后期换框架可以、换渲染模式基本等于重写。

最后给一个 quick reference:后台选 CSR、电商选 SSR、内容站选 SSG、大型站选 ISR、复杂 Web App 选 RSC、文档 + 工具混搭选 Astro Islands。