在 React + Nest.js 项目里做混合 SSR(不是 RSC)
为一个 React + Nest.js 的前后端分离项目,针对特定路由增加服务端渲染(SSR + Hydration)。注意:本文讨论的是传统 SSR 水合,不是 React Server Components(RSC)。
先分清:SSR ≠ RSC
| 概念 | 是什么 |
|---|---|
| SSR | 服务端把组件渲染成 HTML 字符串发回浏览器,客户端再 hydrate 挂上事件与状态 |
| RSC | React 的服务端组件模型:服务端组件代码默认不进客户端包,通过 Server/Client 边界与 Flight 协议协作 |
下文全程是 SSR + Hydration 的混合渲染改造,不要和 RSC 混为一谈。
从纯 CSR 到混合渲染
在现代 Web 开发中,前后端分离已经成为主流,便于在浏览器上实现复杂交互。
但并非所有内容都需要在客户端用 JS 驱动。许多数据展示页只是“载入数据并展示”,纯 CSR 会让首屏几乎空白、依赖后续 JS 渲染,在加载性能和 SEO 上有明显短板。
当我们的项目逐渐成熟,希望优化关键页面(如用户个人资料页、产品详情页)的加载性能和 SEO 时,是否必须推倒重来,迁移到 Next.js 或 Remix 这类一体化框架?
答案是:不必。我们完全可以在现有的 CSR + API 架构上,通过“混合渲染”的模式,针对性地为特定路由增加服务端渲染 (SSR) 功能。本文以一个 React + Nest.js项目,为 /user 路由添加服务端渲染为例。(伪代码,仅供思路参考)
核心思想:从“分离”到“协作”
要实现混合渲染,我们需要调整前后端的角色定位:
Nest.js 的角色扩展:对于大部分 API 请求,它依然是纯粹的 API 服务器。但对于 /user 这个特定路由的 GET 请求,它将化身为一个 Web 服务器,负责:
调用内部服务获取数据。
在服务端将 React 组件和数据“渲染”成一份完整的 HTML 字符串。
将这份 HTML 返回给浏览器。
React 的“水合”(Hydration):浏览器先展示服务端 HTML,客户端 React 加载后接管已有 DOM,挂上事件与状态,让页面变成可交互的 SPA,而不是推倒重建。
其他路由保持不变:除了 /user,如 /dashboard、/settings 仍可走纯 CSR,由 React Router 控制,后端只提供 API。
sequenceDiagram
participant B as 浏览器
participant N as Nest.js
participant R as React 服务端渲染
participant API as 内部服务/DB
B->>N: GET /user
N->>API: 取页面数据
API-->>N: user
N->>R: renderToString(UserPage, props)
R-->>N: HTML 片段
N-->>B: 完整 HTML + 初始数据脚本
B->>B: 展示内容
B->>B: 加载 JS 后 hydrateRoot 接管