不推荐从零手写SSR同构架构,Next.js、Nuxt.js或SvelteKit已覆盖95%场景;仅当有首屏性能、数据流控制或微前端集成等极端定制需求时才需自研。

直接上结论:不推荐从零手写 SSR 同构架构,Next.js、Nuxt.js 或 SvelteKit 已覆盖 95% 的业务场景;真正需要自研的,只发生在对首屏性能、数据流控制或微前端集成有极端定制需求时。
为什么 renderToString 在服务端跑不通?
常见错误是组件里直接用了 window、document、localStorage 或依赖 DOM 的第三方库(比如某些图表插件)。Node.js 环境没有这些对象,一执行就报 ReferenceError: window is not defined。
- 所有浏览器专属逻辑必须包裹在
typeof window !== 'undefined'条件判断中 - 路由守卫、动画初始化、第三方 SDK 加载等,应放在
useEffect(React)或onMounted(Vue)里 - 避免在组件顶层声明依赖
document的变量,比如const el = document.getElementById('xxx') - 使用动态导入隔离 CSR-only 组件:
const Chart = dynamic(() => import('../components/Chart'), { ssr: false })
getServerSideProps 和 asyncData 怎么选数据源?
这两个函数本质都是服务端数据预取入口,但行为差异直接影响首屏速度和 SEO 可靠性。
-
getServerSideProps(Next.js)每次请求都执行,适合实时性高、用户个性化强的数据,比如仪表盘、订单详情 -
asyncData(Nuxt.js)默认也走服务端,但可配合fetch+key实现客户端缓存复用,减少重复请求 - 不要在其中调用未封装的
fetch或axios实例——它们可能隐式依赖window或未配置服务端超时 - 数据必须序列化为纯 JSON,不能含
Date、RegExp、Map等非可序列化类型,否则 hydration 会失败
状态怎么从服务端“倒”到客户端?
服务端渲染完 HTML,客户端必须用完全一致的状态去 hydrate,否则 React/Vue 会抛出 Hydration failed because the initial UI does not match what was rendered on the server 警告,甚至丢弃整个 DOM 树重新挂载。
- Next.js 自动把
getServerSideProps返回的对象注入props,无需手动处理 - Nuxt.js 默认将
asyncData结果挂到组件$data,但若用 Vuex/Pinia,需显式调用store.replaceState() - 自研方案中,常用
<script id="__INITIAL_STATE__" type="application/json">{...}</script>注入,客户端用JSON.parse(document.getElementById('__INITIAL_STATE__').textContent)读取 - 务必确保服务端与客户端使用同一份状态初始化逻辑,比如时间戳生成、随机 ID 生成器等,都要加环境判断或固定 seed
最常被忽略的点是 CSS 注入顺序和样式水合。服务端生成的 标签如果位置不对,或者客户端样式加载时机晚于 hydration,会导致 FOUC(Flash of Unstyled Content)——这个细节在框架文档里往往一笔带过,但在线上环境极易暴露。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











