服务端渲染(SSR)指服务器在请求时执行JS生成完整HTML返回,核心是renderToString等函数在Node.js中运行且组件须无浏览器依赖;CSR则仅返回空壳HTML,由浏览器下载JS后渲染,首屏慢、SEO差;SSR非必然更快,需严格同构、数据一致与环境隔离。
JavaScript 服务端渲染(SSR)不是指“用 Node.j
s 跑 React/Vue”,而是指:在用户请求页面时,服务器执行 JavaScript 渲染逻辑,生成完整的 HTML 字符串并返回,而不是只发一个空壳 index.html 让浏览器自己拉 JS、再渲染。
renderToString 或等效函数以 React 为例,关键动作是调用 ReactDOMServer.renderToString()(或 renderToPipeableStream()),把组件树同步/流式转成 HTML 字符串;Vue 则用 vue-server-renderer 的 renderToString()。这些函数必须运行在 Node.js 环境中,且组件不能依赖浏览器全局对象(如 window、document)。
常见错误现象:
useEffect 或 componentDidMount 里的 DOM 操作 —— 会报 ReferenceError: document is not defined
renderToString 前未正确注入初始数据(如 Redux state、路由匹配结果),导致首屏 HTML 缺内容canvas)传统 CSR 应用打包后只有一个极简的 index.html,里面只有 和一个 标签。浏览器下载 JS 后才开始解析组件、发起 API 请求、构建 DOM —— 这意味着首屏白屏时间长、SEO 不友好、首屏无法直出内容。
关键差异点:
ReactDOM.hydrateRoot()(或旧版 hydrate())只是“激活”已存在的 HTML,不做真实渲染;而 SSR 的 renderToString() 是真渲染getServerSideProps)SSR 把渲染压力从用户设备转移到服务器,但换来的是更复杂的部署、更高的内存/CPU 开销、以及对代码同构性的严苛要求。比如:
Text content does not match)localStorage、navigator.geolocation 这类纯浏览器 API,不能在 SSR 阶段访问 —— 必须包裹在 if (typeof window !== 'undefined') 或生命周期钩子中if (typeof window !== 'undefined') {
// 这里才能安全使用 localStorage
const savedTheme = localStorage.getItem('theme');
}
Next.js、Nuxt、Remix 等框架封装了服务端渲染的底层细节,但它们仍强制你区分“服务端可执行”和“仅客户端可用”的代码位置:
getServerSideProps 函数内可以发请求、读文件、连接数据库;但它不能包含任何浏览器 API 调用asyncData 和 fetch 钩子会在服务端和客户端都执行,但服务端执行结果会序列化进 HTML 的 ,避免客户端重复请求loader 函数天然只运行在服务端,数据不会泄漏到客户端,安全性更高真正难的不是“怎么开启 SSR”,而是怎么让组件既能在 Node.js 里跑通,又能在浏览器里正确 hydrate —— 很多 bug 都藏在数据一致性、副作用时机、环境判断漏判里。