在历史项目升级中用SSR和SSG优化性能的实现流程
核心目标: 让用户第一次打开页面时,看到内容更快(减少白屏/加载转圈),并且减轻浏览器的负担,从而提升整体性能,尤其是对老项目或者低端设备用户特别友好。
简单理解两者:
-
SSR (服务端渲染 - Server-Side Rendering):
-
比喻: 想象你去餐厅点菜。SSR 就是厨房(服务器)把菜(完整的 HTML 页面)完全做好、摆好盘,直接端到你桌上(浏览器)。你坐下就能开吃(看到完整内容)。
-
关键点: 用户请求页面时,服务器实时运行你的前端代码(React/Vue等),获取数据,生成包含最终内容的 HTML,然后发给浏览器。浏览器下载后,内容已经在了,只需要“激活”交互功能(Hydration)。
-
-
SSG (静态站点生成 - Static Site Generation):
-
比喻: 还是餐厅,但这次是自助餐。厨房(构建过程)在开门营业前(用户访问前) 就把所有可能受欢迎的菜(HTML页面)都提前做好、摆好在餐台上。用户来了,直接拿现成的吃(获取预先生成的静态文件)。
-
关键点: 在你发布网站时(
npm run build
),工具会预先运行你的前端代码,获取所有需要的数据,为每一个可能的页面生成纯 HTML、CSS、JS 文件。用户访问时,CDN 直接把这些“成品”文件快速送过去,几乎不需要服务器实时计算。
-
为什么能优化性能?
-
首屏速度快: 用户拿到的是包含内容的 HTML,不是空壳子或加载动画。浏览器能立刻渲染内容,用户感觉“秒开”。
-
减少浏览器压力: 服务器或构建过程承担了组装页面的重活,老旧的用户设备只需要负责显示和简单的交互,负担小很多。
-
更好的 SEO: 搜索引擎爬虫拿到的是完整的 HTML 内容,更容易理解页面信息。
-
减轻服务器负担 (SSG): SSG 的页面是纯静态文件,可以被 CDN 高效缓存,服务器只在构建时忙一下,用户访问时几乎零压力。
-
更稳定的 TTFB (SSG): 静态文件返回速度极快,用户等待服务器响应的第一字节时间大大缩短。
在历史项目中实施的流程 :
假设有一个基于 React 的老项目(Vue/Angular 原理类似),之前是纯 CSR (客户端渲染) - 即浏览器下载一个空壳 HTML 和一堆 JS,然后 JS 再去请求数据、组装页面,导致首屏慢。
步骤 1:选好工具 (架锅烧油)
-
你需要一个支持 SSR 和 SSG 的框架或库。最常见的选择:
-
Next.js (React): 目前最流行、最成熟,对 SSR/SSG 支持开箱即用,文档丰富,社区庞大。强烈推荐历史项目迁移使用。
-
Nuxt.js (Vue): Vue 生态的类似方案,同样优秀。
-
Gatsby (React, 更侧重 SSG/数据驱动): 非常适合博客、文档、营销页等偏静态内容。
-
Angular Universal (Angular): Angular 官方的 SSR 解决方案。
-
-
选择建议: Next.js/Nuxt.js 通常是最平滑的升级路径,因为它们提供了完整的应用结构和路由方案。
步骤 2:项目改造 (准备食材)
-
安装依赖: 用 npm/yarn 安装你选择的框架(以Next.js为例,如
npm install next react react-dom
)。 -
调整项目结构:
-
框架(如 Next.js)有特定的目录约定(如
pages/
,public/
,getStaticProps
,getServerSideProps
)。你需要把旧项目的页面组件迁移到这些约定目录下。 -
可能需要拆分组件,把数据获取逻辑从组件内部移到框架提供的方法中。
-
-
路由改造:
-
框架通常有自己基于文件系统的路由(
pages/about.js
->/about
)。你需要将旧的路由配置(如 React Router)迁移或适配到这个新路由系统。Next.js 的路由基本是自动的,非常省心。
-
-
数据获取改造 (最关键!):
-
识别哪些数据用于渲染页面: 是商品列表?用户信息?文章内容?
-
决定用 SSR 还是 SSG:
-
SSG (
getStaticProps
- Next.js 为例): 如果页面内容在构建时就能确定,或者更新频率很低(一天几次),或者可以接受构建后才更新。比如:博客文章、产品介绍页、公司“关于我们”页、营销活动页。在page
组件文件中导出async getStaticProps()
函数,在里面获取数据并return { props: { ... } }
。这些数据会在构建时传给组件生成静态 HTML。 -
SSR (
getServerSideProps
- Next.js 为例): 如果页面内容每次请求都可能不同,或者需要访问请求对象(req
/res
,比如拿 Cookie 做用户认证),或者数据必须实时性极高(秒级更新)。比如:用户个人中心页、带实时数据的仪表盘、依赖用户登录态的页面。在page
组件文件中导出async getServerSideProps(context)
函数,在里面获取数据并return { props: { ... } }
。这个函数在每次用户请求该页面时在服务器运行,生成带数据的 HTML。 -
ISR (增量静态再生 - Next.js 独有, 超好用!): SSG 的升级版。先按 SSG 生成静态页面并缓存。可以设置一个
revalidate
时间(秒)。在revalidate
时间内访问,直接返回缓存(超快)。过了时间后的第一次访问,后台会重新生成新页面,下次访问用新的;同时这次访问依然返回旧的缓存(用户无感知)。完美平衡速度和新鲜度!非常适合新闻列表、商品列表等。
-
-
改造 API 调用: 原来在组件
useEffect
里或组件挂载时发起的 API 请求,要挪到getStaticProps
/getServerSideProps
中去。组件本身变成主要接收props
来渲染。
-
-
处理客户端专有代码 (处理鱼刺):
-
像访问
window
,document
,localStorage
这样的浏览器特有对象,在服务器环境(SSR/SSG 构建时)是不存在的! -
需要把这些代码放到:
-
useEffect
钩子中(只在客户端运行) -
或者用
if (typeof window !== 'undefined') { ... }
判断 -
或者动态导入(
dynamic import
)包含这类代码的组件,并设置ssr: false
(Next.js:dynamic(() => import('...'), { ssr: false })
)
-
-
步骤 3:构建与部署 (开火烹饪)
-
开发环境 (
npm run dev
): 框架会同时支持 CSR、SSR 和 SSG 的开发预览,方便调试。 -
生产构建 (
npm run build
- Next.js 为例):-
框架会分析你的页面:
-
标记了
getStaticProps
的页面 -> 走 SSG 流程。在构建阶段调用getStaticProps
,获取数据,为每个页面生成静态 HTML 文件(可能还有 JSON 数据文件)。如果用了动态路由(pages/posts/[id].js
),它会根据getStaticPaths
返回的路径列表生成所有可能的静态页面。 -
标记了
getServerSideProps
的页面 -> 走 SSR 流程。不生成静态 HTML,但会准备好服务器运行时代码。用户请求时服务器实时渲染。 -
没标记的页面 -> 默认是 CSR。
-
-
生成优化后的 JS/CSS 等静态资源。
-
-
部署:
-
SSG 页面: 生成的纯 HTML/CSS/JS 文件可以部署到任何静态托管平台 (Vercel, Netlify, GitHub Pages, AWS S3 + CloudFront 等)。它们通常有全球 CDN,访问速度极快。
-
SSR 页面: 需要部署到一个能运行 Node.js 的服务器环境 (Vercel, Netlify Functions, AWS Lambda, 自己的 Node 服务器,Docker 容器等)。当用户请求 SSR 页面时,这个服务器环境会执行
getServerSideProps
和渲染逻辑。 -
混合部署 (推荐): 大部分项目都是混合的!首页、博客文章用 SSG/ISR;用户个人中心、搜索页用 SSR。像 Vercel (Next.js 亲爹) 能智能处理:收到请求,如果是 SSG 且有缓存,CDN 直接返回;如果是 SSR 或 SSG 缓存过期(ISR),就调用服务器函数渲染。开发者几乎不用操心。
-
步骤 4:监控与调优 (尝咸淡,调火候)
-
性能测试: 用 Lighthouse, WebPageTest 等工具测试升级前后的关键指标:FCP (首次内容绘制), LCP (最大内容绘制), TTI (可交互时间), TTFB (首字节时间)。看优化效果。
-
分析包大小: 框架的构建输出通常包含分析工具(Next.js:
npm run build -- --analyze
),查看生成的 JS 包,优化过大的依赖。 -
CDN 配置: 确保静态资源(包括 SSG 页面)设置了合理的缓存头,充分利用 CDN 缓存。
-
ISR 调优: 根据数据更新频率调整
revalidate
时间。对于海量页面,可以用fallback
模式(getStaticPaths
中返回部分路径,其他路径在首次访问时按需生成并缓存)。
总结一下关键流程:
-
选武器: Next.js/Nuxt.js 等框架。
-
搬家具: 按框架要求调整项目结构、路由。
-
改数据拿法 (核心!):
-
不变的/更新慢的页面 -> SSG (
getStaticProps
): 构建时生成好,飞快! -
每次访问都变的/需要
req
的页面 -> SSR (getServerSideProps
): 服务器实时做,保证新鲜。 -
想又快又相对新鲜 -> ISR (
revalidate
): 缓存+后台更新,真香!
-
-
避坑: 把只能在浏览器运行的代码 (
window
,document
) 包起来。 -
建造&发布:
build
命令生成文件,部署到合适的平台(静态托管给 SSG,Node 环境给 SSR)。 -
看看效果: 测速、分析、调缓存。
人话精髓:
-
SSG: 提前把页面像做预制菜一样做好存冰箱(CDN),用户点单(访问)直接微波炉加热(快速发送),省时省力速度快!适合内容固定的页面。
-
SSR: 用户点单(访问)后,厨师(服务器)现场开火炒菜(实时获取数据+渲染),保证菜是热的(数据最新),但等菜时间稍长一点。适合内容实时性要求高的页面。
-
升级关键: 把老项目中“在浏览器里现场炒菜”(CSR)的部分,改成要么“提前做好预制菜”(SSG),要么“让服务器大厨代炒”(SSR)。改造的重点就是怎么拿数据和什么时候生成页面。
这样改造下来,历史项目就能焕发新生,用户打开速度嗖嗖的,体验提升立竿见影!
ps: 知识学习整理的简单记录,如有不严谨之处,欢迎指正