使用Next.js进行增量静态再生(ISR)的完整指南

4,616 阅读9分钟

一年前,Next.js 9.3发布了对静态网站生成(SSG)的支持,使其成为第一个混合框架。这时我已经是Next.js的快乐用户了,但这次发布使Next.js成为我新的默认解决方案。在广泛使用Next.js后,我加入了Vercel,帮助Tripadvisor和华盛顿邮报等公司采用和扩展Next.js。

在这篇文章中,我想探讨Jamstack的一个新的演变。增量式静态再生(ISR)。下面你会看到ISR的指南--包括用例、演示和权衡。

静态站点生成的问题

Jamstack背后的想法很吸引人:预先渲染的静态页面可以被推送到CDN,并在几秒钟内全球可用。静态内容速度快,对停机时间有弹性,并能立即被爬虫索引。但也有一些问题。

如果你在建设大规模静态网站时采用了Jamstack架构,你可能会被卡住,等待你的网站建设几个小时。如果你的页面数量增加一倍,构建时间也会增加一倍。让我们考虑Target.com。是否有可能在每次部署时都静态地生成数以百万计的产品?

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

内容管理系统(CMS)

对于许多团队来说,他们网站的内容与代码是脱钩的。使用无头CMS允许内容编辑者在不涉及开发人员的情况下发布更改。然而,对于传统的静态网站,这个过程可能很慢。

考虑到一个有100,000种产品的电子商务商店。产品价格经常变化。当一个内容编辑将耳机的价格从100美元改为75美元作为促销的一部分时,他们的CMS使用网络钩子来重建整个网站。等待几个小时来反映新的价格是不可行的。

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

递增式静态再生(ISR

Next.js允许你_在_建立网站_后_创建或更新静态页面。增量静态再生(ISR)使开发人员和内容编辑人员能够在每个页面的基础上使用静态生成,而不需要重建整个网站。通过ISR,你可以保留静态的好处,同时扩展到数百万个页面。

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

考虑一下前面那个有10万个产品的电子商务商店。在一个现实的50ms静态生成每个产品页面的情况下,如果没有ISR,这将需要将近2小时。有了ISR,我们可以选择。

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

让我们来看看一个电子商务产品页面的ISR例子。

开始吧

抓取数据

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

  1. Next.js可以为每个页面定义一个重新验证的时间。让我们把它设置为60秒。
  2. 对产品页面的初始请求将显示带有原始价格的缓存页面。
  3. 产品的数据会在CMS中更新。
  4. 在初始请求之后和60秒之前,对该页面的任何请求都会被缓存并即时生效。
  5. 在60秒的窗口之后,下一次请求仍然会显示缓存的(陈旧的)页面。Next.js会_在后台_触发页面的再生。
  6. 一旦页面成功生成,Next.js将使缓存失效并显示更新的产品页面。如果后台再生失败,旧的页面就不会被改变。
// pages/products/[id].js

export async function getStaticProps({ params }) {
  return {
    props: {
      product: await getProductFromDatabase(params.id)
    },
    revalidate: 60
  }
}

生成路径

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

我们需要配置Next.js在初始构建后请求任何其他产品时的 "回退 "方式。有两个选项可以选择:blockingtrue

  • fallback: blocking (首选)
    当请求到一个尚未生成的页面时,Next.js将在第一次请求中对该页面进行服务器渲染。以后的请求将从缓存中提供静态文件。
  • fallback: true
    当向一个尚未生成的页面发出请求时,Next.js将在第一次请求时立即提供一个具有加载状态的静态页面。当数据加载完毕后,页面将以新的数据重新渲染并被缓存。未来的请求将从缓存中提供静态文件。
// pages/products/[id].js

export async function getStaticPaths() {
  const products = await getTop1000Products()
  const paths = products.map((product) => ({
    params: { id: product.id }
  }))

  return { paths, fallback: ‘blocking’ }
}

权衡利弊

Next.js首先关注的是终端用户。最佳解决方案 "是相对的,并因行业、受众和应用程序的性质而异。Next.js允许开发者在不离开框架的情况下在不同的解决方案之间转换,让你为项目挑选合适的工具。

服务器端渲染

ISR并不总是正确的解决方案。例如,Facebook的新闻源不能显示陈旧的内容。在这种情况下,你会想使用SSR和可能是你自己的cache-control headers,用代理键来使内容失效。由于Next.js是一个混合框架,你能够自己做出这种权衡,并保持在框架内。

// You can cache SSR pages at the edge using Next.js
// inside both getServerSideProps and API Routes
res.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate');

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

注意在没有缓存的情况下使用SSR会导致性能下降。在阻止用户看到你的网站时,每一毫秒都很重要,这对你的TTFB(第一个字节的时间)会有很大的影响。

静态网站的生成

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

客户端渲染

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

由于缺乏来自初始HTML的预渲染内容,导致搜索引擎优化(SEO)速度更慢,动态更少。也不可能在禁用JavaScript的情况下使用CSR。

ISR后退选项

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

ISR:不仅仅是缓存

虽然我已经通过缓存的上下文解释了ISR,但它的设计是为了在不同的部署中持久化你生成的页面。这意味着你能够立即回滚,而不会丢失你以前生成的页面。

每个部署都可以用一个ID键入,Next.js用它来保持静态生成的页面。当你回滚时,你可以更新密钥以指向之前的部署,从而实现原子式部署。这意味着,你可以访问你以前的不可变的部署,它们将按计划工作。

  • 下面是一个用ISR恢复代码的例子。
  • 你推送代码并得到一个部署ID 123。
  • 你的页面包含一个错字 "Smshng Magazine"。
  • 你在CMS中更新该页面。不需要重新部署。
  • 一旦你的页面显示 "Smashing Magazine",它就会被持久化在存储中。
  • 你推送了一些糟糕的代码,并部署了ID 345。
  • 你回滚到部署ID 123。
  • 你仍然看到 "Smashing Magazine"。

回滚和持久化静态页面不属于Next.js的范围,取决于你的托管服务提供商。请注意,ISR与使用Cache-Control headers的服务器还原不同,因为根据设计,缓存会过期。它们不是跨区域共享的,在还原时将会被清除掉。

递增式静态再生的例子

递增式静态再生对电子商务、营销页面、博客文章、广告支持的媒体等都很有效。

  • 电子商务演示
    Next.js Commerce是一个用于高性能电子商务网站的多合一入门套件。
  • GitHub反应演示
    对GitHub的原始问题进行反应,并观看ISR更新静态生成的登陆页面。
  • 静态推文演示
    该项目在30秒内完成部署,但可以使用ISR按需静态生成500万条推文。

今天就学习Next.js

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

Next.js是为逐步采用而设计的。使用Next.js,你可以继续使用你现有的代码,并根据你的需要添加尽可能多(或尽可能少)的React。通过从小处着手,逐步增加页面,你可以避免完全重写,从而防止功能工作脱轨。了解更多关于Next.js的信息--祝大家编码愉快!

进一步阅读