原文地址: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。有可能每次部署都静态生成数百万个产品页面吗?
静态网站生成的问题:由于创建时间与页面数量呈线性关系,因此你可能需要等待数小时才能创建网站。
即使每个页面都在不现实的 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 分钟构建)。
ISR 的优势:你可以灵活选择在构建时或按需生成哪些页面。可以选择 (A) 更快的构建或 (B) 更多的缓存。
让我们以电子商务产品页面为例,了解一下 ISR。
入门
获取数据
如果你以前从未使用过 Next.js,我建议你阅读 《Next.js 入门》以了解基础知识。ISR 使用与 Next.js 相同的 API 来生成静态页面:getStaticProps。通过指定 revalidate: 60,我们通知 Next.js 在此页面中使用 ISR。
增量静态再生的请求流程图:
- Next.js 可以定义每个页面的重新验证时间。我们将其设置为 60 秒。
- 对产品页面的初始请求将显示带有原始价格的缓存页面。
- 产品数据将在内容管理系统中更新。
- 在初始请求之后和 60 秒之前对页面的任何请求都会被缓存并即时显示。
- 60 秒窗口过后,下一次请求仍将显示缓存(陈旧)页面。Next.js 会在后台触发页面再生。
- 一旦页面成功生成,Next.js 就会使缓存失效,并显示更新后的产品页面。如果后台再生失败,旧页面将保持不变。
生成路径
Next.js 定义了哪些产品在构建时生成,哪些按需生成。通过向 getStaticPaths 提供前 1000 个产品 ID 的列表,让我们在构建时至生成最受欢迎的 1000 个产品。
我们需要配置 Next.js 在初始构建后请求其他产品时的 "fallback" 方式。有三个选项可供选择:false、true 和 blocking。
- 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 标头的服务端渲染,因为根据设计,缓存会过期。它们不会跨区域共享,并会在还原时被清除。
增量静态再生示例
增量静态再生技术适用于电子商务、营销页面、博客文章、广告支持媒体等。
- E-commerce Demo:Next.js Commerce 是高性能电子商务网站的入门模板。
- GitHub Reactions Demo:监听 GitHub issue,并使用 ISR 更新界面。
- Static Tweets Demo:该项目可在 30 秒内完成部署,可使用 ISR 按需静态生成 500M tweets。
理解学习 Next.js
开发人员和大型团队之所以选择 Next.js,是因为它的混合方法和按需增量生成页面的能力。通过 ISR,你可以获得静态的优势和服务端渲染的灵活性。ISR 可使用 next start 开箱即用。
Next.js 转为逐步采用而设计。使用 Next.js,你可以继续使用现有代码,并根据需要添加尽可能多(或尽可能少)的 React。通过从小规模开始并逐步添加更多的页面,你可以避免完全重写,从而避免功能工作脱轨。这里可以了解有关 Next.js 的更多信息。
最后,祝大家编码愉快。
进一步阅读
感谢 Lee Robinson。