出处:掘金
原作者:某某某人
CSR(Client Side Rendering)
客户端渲染
是指在客户端使用 JS 来渲染页面。服务器只负责提供数据,所有的渲染工作都在客户端进行
一图胜千言
- 用户访问页面:用户在浏览器中输入 URL,浏览器向服务器发送请求
- 服务器返回资源:服务器接收到请求后,会返回一个基础的 HTML,这个 HTML 通常只包含一个空的 div 元素和一些 JS 脚本的引用
- 浏览器解析 HTML:浏览器接收到 HTML 后,会开始解析 HTML,并构建 DOM 树。因为 HTML 中只有一个空的 div 元素,所以这个过程非常快
- 浏览器下载 JS 文件:浏览器会开始下载 HTML 中引用的 JS 文件。这些 JS 文件包含了 React/Vue 库和组件的代码
- 浏览器解析 JS 文件:当 JS 文件下载完成后,浏览器会开始解析 JS 文件,并执行其中的代码。在这个过程中,React/Vue 会创建组件,并将这些组件渲染到空的 div 元素中
- 获取数据:在 CSR 的架构下,数据通常是在客户端获取的。当 React/Vue 组件需要数据时,会发送 AJAX 请求到服务器,获取数据,然后使用这些数据来更新页面
- 更新页面:当数据返回后,React/Vue 会使用这些数据来更新组件,然后重新渲染页面。这个过程是动态的,可以在用户访问页面后的任何时刻进行
SSR(Server Side Rendering)
服务器端渲染
是指在服务器端将页面和数据渲染成 HTML 字符串并返回给客户端
一图胜千言
- 用户访问页面:用户在浏览器中输入 URL,浏览器向服务器发送请求
- 服务器接收请求:服务器接收到用户的请求后,会根据请求的 URL 动态确定需要渲染哪个页面
- 获取数据:在 Next.js 中,可以使用
getInitialProps
或getServerSideProps
等函数来在服务器端获取数据。这些函数会在服务器端运行,并且可以接收到请求的上下文(包括请求的参数、头部信息等),因此可以根据请求的信息来获取数据 - 渲染页面:服务器端获取到数据后,会将数据传递给 React 组件,然后使用 React 的
renderToString
函数将 React 组件渲染成 HTML 字符串 - 返回客户端:服务器将拼接好的 HTML 发送给客户端,客户端接收到 HTML 后,浏览器会解析 HTML 并显示页面
- 注水:在 HTML 中,Next.js 会将服务器端获取到的数据以 JSON 的形式嵌入到一个 script 标签中,这个过程叫做注水
- 脱水:Next.js 的运行时脚本会读取这个 script 标签中的数据,然后将数据传递给 React 组件,这个过程叫做脱水
- 水合(Hydration):React 会对比服务器端渲染的 HTML 和使用脱水得到的数据来渲染客户端的 React 组件,然后尽可能地复用服务器端渲染的 HTML。这个过程可以提高性能,因为不需要重新生成和插入 DOM 元素,同时会为客户端的 React 组件绑定事件处理函数。这样,当用户和页面进行交互时,就可以触发这些事件处理函数
- 激活页面:Hydration 完成后,页面就被激活了,用户可以和页面进行交互。在这个过程中,如果用户触发了一些需要获取数据的操作,Next.js 会在客户端获取数据,并更新页面
SSG(Static Site Generation)
静态网站生成
是指在构建阶段将页面渲染成 HTML 文件,然后将 HTML 文件部署到 CDN 上。用户访问页面时,服务器直接返回静态的 HTML 文件
一图胜千言
- 获取数据:在 Next.js 中,可以使用
getStaticProps
函数来在构建阶段获取数据。这个函数会在 Node.js 环境中运行,因此可以访问服务端数据库,或者请求其他服务端接口。获取到的数据会被传递给 React 组件 - 渲染 React 组件:Next.js 会使用获取到的数据来渲染 React 组件。这个过程和在浏览器中渲染 React 组件的过程是一样的,只是运行环境不同。在这个过程中,React 组件会被转化为 HTML 字符串
- 注水:Next.js 会将获取到的数据以 JSON 的形式嵌入到 HTML 中,这个过程被称为注水。这样做的目的是为了将数据传递给客户端
- 生成静态文件:Next.js 会将渲染出来的 HTML 字符串和注水的数据一起保存为静态文件,通常是
.html
文件。这些静态文件会被部署到 CDN 上 - 用户访问页面:用户在浏览器中输入 URL,浏览器向服务器发送请求,服务端返回提前创建好的 HTML 给浏览器
- 脱水:和 SSR 一样,Next.js 会在 HTML 中嵌入服务器端获取到的数据,然后在客户端提取出这些数据
- 水合(Hydration):Next.js 会使用 React 的
hydrate
函数,将服务器端渲染的 HTML 和客户端的 React 组件进行对比,然后复用服务器端渲染的 HTML - 激活页面:Hydration 完成后,页面就被激活了,用户可以和页面进行交互
方案对比
方案 | CSR | SSR | SSG |
---|---|---|---|
动态性 | 高 | 高 | 低 |
首屏性能 | 差 | 优 | 优 |
SEO | 差 | 优 | 优 |
成本 | 无 | 消耗服务端资源 | 主要工作在构建阶段,成本较低 |
适用场景
- CSR 适合那些需要丰富用户交互,不需要 SEO 的应用,如 Web 应用、后台管理系统等
- SSR 适合那些需要快速首屏加载和 SEO 的应用,如新闻网站、电商网站等
- SSG 适合那些结构内容相对固定,不需要实时数据的应用,如博客网站、文档网站等
补充
这里补充一个使用 Vue 2.7 使用 SSG 遇到的一个坑,在 Hydration 阶段如果客户端生成的 DOM 和预渲染的静态 DOM 不一致。在开发环境是会弃用预渲染的 DOM,直接使用客户端生成的 DOM 树来渲染;但是在线上环境并不是这样,而是会直接使用静态的 DOM,导致页面部分是静态的不能交互的
具体代码 patch_hydrate: