讲清楚 Next.js 里的 CSR, SSR, SSG 和 ISR
在 Web 前端的圈子里,渲染是一个无法绕开的概念。渲染决定了用户能够看到什么,以及他们能多快看到。但是,所有的渲染不都是相同的。随着现代前端开发的演进,我们有了多种不同的渲染方式,每种都有其独特的优势和挑战。
Next.js 作为 React 的上层框架,为开发者提供了一系列强大的渲染方式——从传统的客户端渲染(CSR)到服务器端渲染(SSR),再到静态网站生成(SSG)和最新的增量静态生成(ISR):每一种方法都有其适用的场景。
思考一下,为什么我们需要这么多的渲染策略?它们之间有什么不同?如何为你的项目选择合适的策略?在本篇文章中,我们将详细探讨这些问题,一起来深入了解 Next.js 的渲染策略。
客户端渲染 (CSR)
客户端渲染(CSR)是 React 应用程序的默认渲染策略。在 CSR 中,应用首次渲染会加载一个最小的 HTML 文件,其中包括负责渲染 DOM 的 JavaScript 文件。然后,由浏览器执行 JavaScript,从 API 获取数据并完成渲染。
Next.js 中在 useEffect() 中请求数据就属于 CSR:
这个示例中,在请求完成前会显示Loading,请求完成后就会把请求结果渲染到页面。
优缺点
优点:
- 服务器负载较轻,因为大部分工作都在客户端完成。
- 适用于高度交互的应用,如 SPA (单页应用)。
- 一旦页面加载完成,页面间的导航和互动会非常迅速。
缺点:
- 首次加载时间可能较长,因为需要下载、解析和执行大量 JavaScript。
- 不利于 SEO,因为搜索引擎可能只看到空的 HTML,而不是实际内容。
- 增加了客户端的计算负担,可能导致手机等低功耗设备的性能问题。
服务器端渲染 (SSR)
Next.js 中,要使用服务器端渲染,需要导出一个名为 getServerSideProps
的异步函数。服务器将在每次请求页面时优先调用该函数。
例如,假设页面需要预渲染频繁更新的数据(如下截图的页面访问量)。那你就可以编写 getServerSideProps
来获取这些数据并将其传递给页面
这个示例中,页面访问量的数据请求无法再浏览器控制台看到,因为getServerSideProps
是在服务端执行的,页面渲染的时候就可以马上拿到访问量数据,不会像 CSR 那样有延迟。
优缺点
优点:
- 首次加载速度快,因为浏览器立即获得完整的页面内容。
- 有助于 SEO,因为搜索引擎可以直接爬取和索引完整的页面内容。
- 减轻了客户端的计算负担。
缺点:
- 服务器压力较大,尤其是在高流量情况下。
- 总体延迟可能增加,因为每次页面请求都需要服务器处理。
- 可能需要额外的服务器资源和优化。
静态网站生成 (SSG)
如果页面静态网站生成 (SSG),页面 HTML 将在 build 时生成。也就是说,如果你的页面已经发布到生产,这时想修改页面内容,只能重新 build 来完成更新。
Next.js 支持在 build 时生成带数据或者不带数据的 HTML,来看示例,
不带数据的静态页面
带数据的静态页面
带数据的静态页面又区分为两种,一种是页面内容依赖数据,一种是页面路径依赖数据。
页面内容依赖数据
页面内容依赖数据,可以使用getStaticProps
完成构建时的数据拉取
只要页面内使用了getStaticProps
,那么 Next.js 都将在 build 时调用并获取数据,然后把数据传给客户端(即 Blog 组件),最后把客户端代码打包成 HTML。
页面路径依赖数据
页面路径依赖数据,要同时使用getStaticProps
和getStaticPaths
完成构建时的数据拉取。
假设你创建了一个动态路由文件 pages/posts/[id].js
,路由会根据 id 显示博客文章,而这个 id 是什么是由服务端告知客户端的。
getStaticProps
和getStaticPaths
是这样联合使用的:
我们首先要使用getStaticPaths
来获取需要预渲染的路径,然后再使用getStaticProps
获取带有此 id 的博客文章,这样 build 时就能完成依次调用getStaticPaths
和getStaticProps
来实现动态路由的静态页面渲染。
SSG 无疑是几种渲染方式里最快的,所以你应该在较少变动数据的页面尽量使用 SSG。
优缺点
优点:
- 极快的加载速度,因为服务器仅提供预生成的文件。
- 减轻了服务器压力,因为不需要实时渲染。
- 非常适合内容不经常变动的网站或应用。
缺点:
- 不适合内容经常变动或需要实时更新的应用。
- 需要在内容变更时重新生成所有页面。
- 可能需要额外的构建和部署步骤。
增量静态生成 (ISR)
增量静态再生(ISR)建立在 SSG 的基础上,同时又有 SSR 的优点,ISR 允许页面的某些部分是静态的,而其他部分则可以在数据发生变化时动态渲染。ISR 在性能和内容更新之间取得了平衡,因此适用于内容经常更新的站点。
先来看一个示例:
这个示例和 SSG 的示例大同小异,为什么能做到增量渲染呢?核心就在于revalidate
和fallback
。
当我们使用 revalidate
选项时,Next.js 会在 build 时调用一次getStaticProps
,部署生产后,Next.js 还会在达到revalidate
设置的时间间隔后再次运行getStaticProps
,以此更新内容。
fallback
则是用来决定当用户请求一个在构建时未被预渲染的路径时,Next.js 应当怎么处理。它有三种可选值:false
、true
和 **'**blocking**'**
。
fallback: false
:- 当用户请求一个在构建时未被预渲染的路径时,将立即返回 404 页面。
- 这意味着如果路径不在
getStaticPaths
返回的列表中,用户会看到一个 404 错误。
fallback: true
:- 当用户请求一个未被预渲染的路径时,Next.js 会立即提供一个“fallback”版本的页面。这通常是一个空页面或一个加载状态。
- 然后,Next.js 会在后台异步地运行
getStaticProps
来获取页面的数据,并重新渲染页面。一旦页面准备好,它将替换“fallback”版本。 - 这允许页面几乎立即可用,但可能不显示任何实际内容,直到数据被加载并页面被渲染。
fallback: 'blocking'
:- 当用户请求一个未被预渲染的路径时,Next.js 会等待
getStaticProps
完成并生成该页面,然后再提供给用户。 - 这意味着用户会等待,直到页面准备好,但他们会立即看到完整的页面内容,而不是一个空页面或加载状态。
- 当用户请求一个未被预渲染的路径时,Next.js 会等待
优缺点
优点:
- 结合了 SSR 的实时性和 SSG 的速度优势。
- 适合内容经常变动但不需要实时更新的应用。
- 减轻了服务器的压力,同时提供了实时内容。
缺点:
- 相比于 SSG,初次请求可能需要更长的加载时间。
如何选择合适的渲染策略建议
- 高度交互的应用:如果你正在开发一个如单页应用(SPA)那样高度交互的应用,CSR 可能是最佳选择。一旦页面加载,用户的任何交互都将非常迅速,无需再次从服务器加载内容。
- 需要 SEO 优化的应用:如果你的应用依赖于搜索引擎优化,SSR 或 SSG 是更好的选择。这两种方法都会提供完整的 HTML,有助于搜索引擎索引。
- 内容静态但更新频繁的网站:例如博客或新闻网站,ISR 是一个很好的选择。它允许内容在背景中更新,而用户仍然可以快速访问页面。
- 内容基本不变的网站:对于内容很少或根本不更改的网站,SSG 是最佳选择。一次生成,无需再次渲染,提供了最快的加载速度。
- 混合内容的应用:Next.js 允许你在同一个应用中混合使用不同的渲染策略。例如,你可以使用 SSR 渲染首页,使用 SSG 渲染博客部分,而使用 CSR 渲染用户交互部分。
结语
CSR、SSR、SSG、ISR 这些看起来让人头疼的概念,实际上都有适合自己的场景,只要分析场景,结合文档使用就不会再迷茫。
专栏资源
专栏介绍:以实战的角度进行Next.js生态圈的技术栈分享,内容包括但不限于:Next.js理论知识、功能模块设计思路、实战中使用到的技术栈。这是一个长期更新的专栏,我会持续把自己的思考和经验提炼分享出来,欢迎关注我的专栏👇
专栏地址:👉Next.js生态圈实战
专栏演示站:👉Next.js Demos
专栏源码仓库:👉Github - Source Code
交个朋友:👉加入「独立全栈交流群」