Ming
bg

NextJS 增量静态再生(ISR)完整指南

阅读时间 25 分钟

原文地址:A Complete Guide To Incremental Static Regeneration (ISR) With Next.js

作者:Lee Robinson

增量静态再生(ISR)是 Jamstack 的新演进,可让你即时更新静态内容,而无需全面重建网站。Next.js 的混合方法允许你将 ISR 用于电子商务、营销页面、博客文章、广告支持媒体等。

一年前,Next.js 9.3 发布了对静态网站生成(SSG)的支持,使其成为第一个混合框架。在这之前的几年里,我一直是 Next.js 的忠实用户,但这次发布的让 Next.js 成为了我新的默认解决方案。在广泛使用 Next.js 之后,我加入了 Vercel,帮助 Tripadvisor 和 Vashington Post 等公司采用和扩展 Next.js。

在本文中,我想探讨一下 Jamstack 的新演进:增量静态再生(ISR)。以下是 ISR 指南,包括用例、演示和权衡。

静态网站生成的问题

Jamstack 背后的理念非常吸引人:预先渲染的静态页面可以推送到 CDN,并在数秒内全球可用。静态内容速度快,抗宕机能力强,并能立即被爬虫索引,但也存在一些问题。

如果你在构建大型静态网站时采用了 Jamstack 架构,你可能需要等待数小时才能完成网站构建。如果页面数量增加一倍,构建时间也会增加一倍。让我们来看看 Target.com。有可能每次部署都静态生成数百万个产品页面吗?

build-times-regeneration

静态网站生成的问题:由于创建时间与页面数量呈线性关系,因此你可能需要等待数小时才能创建网站。

即使每个页面都在不现实的 1 毫秒内静态生成,重建整个网站也需要数小时。对于大型网络应用而言,选择完全静态网站生成是不可行的。大型团队需要一个更加灵活、个性化的混合解决方案。

内容管理系统(CMS)

对于许多团队来说,他们网站的内容与代码是分离的。使用 Headless CMS 可以让内容编辑人员在不涉及开发人员的情况下发布更改。然而,对于传统的静态网站,这一过程可能会很慢。

考虑一家拥有 100,000 种产品的电子商务商店,产品价格经常变化。当内容编辑将商品的价格从 $100 改为 $75 做为促销的一部分时,他们的内容管理系统就会使用 webhook 来重建整个网站。等待数小时才能反映出新价格是不可行的。

冗长的构建和不必要的计算也可能产生额外的费用。理想的情况是,你的应用程序足够智能,能够了解哪些产品发生了变化,并逐步更新这些页面,而无需完全重建

增量静态再生(ISR)

通过 Next.js,你可以在创建网站后创建或更新静态页面。增量静态再生(ISR)可让开发人员和内容编辑人员按页面使用静态生成功能,而无需重建整个网站。有了 ISR,你可以保留静态生成的优势,同时扩展到数百万个页面。

使用 ISR,静态页面可以在运行时(按需)生成,而不是在构建时生成。利用分析、A/B 测试或其他指标,你可以灵活地对构建时间进行权衡。

考虑到之前的电子商务商店有 100,000 种产品。以 50ms 静态生成每个产品页面计算,如果没有 ISR,这将需要近 2 个小时。有了 ISR,我们可以选择:

  • 更快的构建:在构建时生成最受欢迎的 1,000 种产品。对其他产品的请求将导致缓存缺失,并按需静态生成(1 分钟构建)。
  • 更高的缓存命中率:在构建时生成 10,000 个产品,确保用户在请求之前缓存更多的产品(8 分钟构建)。

generation-regeneration

ISR 的优势:你可以灵活选择在构建时或按需生成哪些页面。可以选择 (A) 更快的构建或 (B) 更多的缓存。

让我们以电子商务产品页面为例,了解一下 ISR。

入门

获取数据

如果你以前从未使用过 Next.js,我建议你阅读 《Next.js 入门》以了解基础知识。ISR 使用与 Next.js 相同的 API 来生成静态页面:getStaticProps。通过指定 revalidate: 60,我们通知 Next.js 在此页面中使用 ISR。

增量静态再生的请求流程图:

regeneration-regeneration

  1. Next.js 可以定义每个页面的重新验证时间。我们将其设置为 60 秒。
  2. 对产品页面的初始请求将显示带有原始价格的缓存页面。
  3. 产品数据将在内容管理系统中更新。
  4. 在初始请求之后和 60 秒之前对页面的任何请求都会被缓存并即时显示。
  5. 60 秒窗口过后,下一次请求仍将显示缓存(陈旧)页面。Next.js 会在后台触发页面再生。
  6. 一旦页面成功生成,Next.js 就会使缓存失效,并显示更新后的产品页面。如果后台再生失败,旧页面将保持不变。


生成路径

Next.js 定义了哪些产品在构建时生成,哪些按需生成。通过向 getStaticPaths 提供前 1000 个产品 ID 的列表,让我们在构建时至生成最受欢迎的 1000 个产品。

我们需要配置 Next.js 在初始构建后请求其他产品时的 "fallback" 方式。有三个选项可供选择:falsetrueblocking

  • false(默认):当请求指向一个尚未生成的页面时,返回 404 页面。如果要创建的路径数量较少,或者不经常添加新的页面数据,则此选项非常有用。
  • true:当请求指向一个尚未生成的页面时,Next.js 会在第一次请求时立即提供一个处于加载状态的静态页面。数据加载完成后,页面将使用新数据重新渲染并缓存。
  • blocking(首选):当请求指向一个尚未生成的页面时,Next.js 将在第一次请求时服务端渲染该页面。以后的请求将从缓存中获取静态文件。


按需重新验证

如果你将 revalidate 时间设置为 60,那么所有访问将在一分钟内看到相同的网站生成版本。要使缓存失效,唯一的办法就是在一分钟后有人访问该页面。

Next.js 12.2.0开始,Next.js 支持按需增量静态再生,可手动清除特定页面的 Next.js 缓存。这样就能在以下情况下更轻松地更新网站:

  • 创建或更新 Headless CMS 中的内容
  • 电子商务元数据更改(价格、描述、类别、评论等)

getStaticProps 中,无需指定 revalidate 即可使用按需重新验证。如果省略 revalidate,Next.js 将使用默认值 false (无重验证),只有在调用 revalidate( ) 时才会按需重新验证页面。

首先,创建一个只有 Next.js 应用程序知道的密钥,该密钥将用于防止未经授权访问重新验证 API 路由。你可以通过以下 URL 结构访问路由(手动或使用 webhook)。



接下来,将密钥作为环境变量添加到您的应用程序中。最后,创建重新验证 API 路由:



权衡

Next.js 首选关注的是最终用户。最佳解决方案是相对的,因行业、受众和应用程序的性质而异。Next.js 允许开发人员在不同的解决方案之间转换,而无需离开框架的范围,从而让你为项目选择合适的工具。

SSR

ISR 并不总是正确的解决方案。例如,Facebook 新闻源不能显示过期内容。在这种情况下,你需要使用 SSR,并可能使用自己的带有代理键缓存控制头来使内容失效。由于 Next.js 是一个混合框架,因此你可以在框架内自行取舍。



SSR 和边缘缓存与 ISR 类似(尤其是在使用 stale-while-revalidate 缓存头的情况下),主要区别在于第一个请求。使用 ISR 时,如果预先渲染,第一个请求可以保证时静态的。即使你的数据库出现故障,或者与 API 的通信出现问题。你的用户仍然可以看到正确提供的静态页面。不过 SSR 允许你根据传入请求自定义页面。

Note:使用 SSR 而不进行缓存会导致性能底下。在阻止用户看到你的网站时,每毫秒都很重要,这对你的 TTFB (第一个字节时间) 产生巨大影响。

SSG

对于小型网站来说,ISR 并不总是有意义的。如果重新验证的时间超过重建整个网站所需的时间,那么还不如使用传统的静态网站生成技术。

CSR

如果使用 React 而不使用 Next.js,那么你使用的就是 CSR(客户端渲染)。你的应用程序提供加载状态,然后在客户端的 JavaScript 中请求数据(如,useEffect)。虽然这确实增加了你的托管选择(因为不需要服务器),但也有代价。

初始 HTML 缺乏预渲染内容,导致搜索引擎优化(SEO)速度更慢,动态性更差。此外,在禁用 JavaScript 的情况下也无法使用 CSR。

ISR

如果可以快速获取数据,可以考虑使用 fallback: blocking。这样,你就不需要考虑加载状态,你的页面将始终显示相同的结果(无论是否缓存)。如果数据获取速度较慢,fallback: true 可以让你立即向用户显示加载状态。

ISR:不仅仅是缓存!

虽然我是通过缓存来解释 ISR 的,但它的目的是在部署之间持久保存生成的页面。这意味着你可以立即回滚,而不会丢失之前生成的页面。

每个部署都可以使用一个 ID 作为键值,Next.js 使用该 ID 来持久化静态生成的页面。回滚时,你可以更新键值,使其指向之前的部署,从而实现原子部署。这就意味着,你可以访问以前的不变部署,它们将按原计划运行。

下面是一个使用 ISR 还原代码的示例:

  • 你推送代码并获得部署 ID 123。
  • 你的页面包含一个错别字 "Smshng Magazine"。
  • 你在 CMS 中更新了页面,无需重新部署。
  • 一旦页面显示 "Smshng Magazine",它就会被持久化存储。
  • 你推送了一些错误代码,部署 ID 为 345.
  • 你回滚到部署 ID 123。
  • 你仍然可以看到 "Smshng Magazine"。

还原和持久化静态页面不在 Next.js 的范围内,取决于你的托管服务提供商。请注意,ISR 不同于使用 Cache-Control 标头的服务端渲染,因为根据设计,缓存会过期。它们不会跨区域共享,并会在还原时被清除。

增量静态再生示例

增量静态再生技术适用于电子商务、营销页面、博客文章、广告支持媒体等。

理解学习 Next.js

开发人员和大型团队之所以选择 Next.js,是因为它的混合方法和按需增量生成页面的能力。通过 ISR,你可以获得静态的优势和服务端渲染的灵活性。ISR 可使用 next start 开箱即用。

Next.js 转为逐步采用而设计。使用 Next.js,你可以继续使用现有代码,并根据需要添加尽可能多(或尽可能少)的 React。通过从小规模开始并逐步添加更多的页面,你可以避免完全重写,从而避免功能工作脱轨。这里可以了解有关 Next.js 的更多信息。

最后,祝大家编码愉快。

进一步阅读

感谢 Lee Robinson。

# NextJS

cd ..