Day08 - 在 Next.js 中使用 pre-rendering (getStaticProps) — Part 2

前言

在前一篇文章中,我们了解了如何使用 getStaticProps 让 Next.js 可以在打包阶段产生静态的 HTML 档案,让使用者在浏览指定网站时,服务器能够回传相对应的 HTML 档案,并且因为静态的 HTML 可以被 cache,所以有利於提升使用者看到网页内容的速度。

此外,还了解怎麽在 dynamic routes 中处理 SSG 的问题,因为 dynamic routes 等於是可以匹配无限的 url,但是 Next.js 不可能花费无限的时间打包档案,因此要使用 getStaticPaths 指定有哪些路径会参与 SSG 的打包过程。

而在 getStaticPaths 我们需要回传一个物件,物件中必须包含两个 key,分别为 paramsfallbackparams 定义的是 SSG 对应的路由有哪些, fallback 则是定义使用者浏览 params 没有定义的页面时的对应方式。

Incremental Static Regeneration

今天要介绍的是 Next.js 的 Incremental Static Regeneration (拿到 Google 翻译会跑出增量静态再生,听起来很中二中名字 ?),这个 feature 对於有大量静态页面的网站非常有帮助。

先举一个例子,在 vercel 的这篇文章中就提到电商网站这个例子,在电商网站中假设有超过 10 万件商品,但是使用者只会搜寻他们想看的商品,并不是所有商品都会被看到,花上大量时间在打包 HTML 档案并不符合成本。

因此,Next.js 实作了一种功能叫做 Incremental Static Regeneration,这个功能是在 next build 打包阶段不用生成所有的页面,而是让页面可以动态的生成,以下有两个概念,在实作时可以取舍:

  • Build Faster: 尽管有 10 万件商品,根据 Google Analytics 过去的纪录,只有 1000 件商品比较热门,所以只要生成 1000 个产品的 HTML,藉此可以减少非常大量的打包时间。
  • Cache More: 如果想要让商品页面一开始就能够被 cache,打包阶段生成 10000 万件商品的页面,也是可行的。


*https://vercel.com/docs/next.js/incremental-static-regeneration*

读者应该已经知道 getStaticPathsfallback 的组合技,便是 Incremental Static Regeneration 的实作。但是这样会存在一个问题,尽管可以动态地打包档案,但是电商网站的商品内容可能会快速变动,什麽时候才会重新打包呢?

根据官方的说法,在没有设定 revalidate 的情况是不会重新生成已经存在的 HTML

尽管,我们可以从 Next.js 官方文件或 Chrome 的 Network 中看到 SSG 预设的 cache 时间是 31536000:

Cache-Control: s-maxage=31536000, stale-while-revalidate

31536000 的单位是秒,所以换算成天的话是 365 天,但是 365 天过後,也只是重新设定 cache 与回传同样的 HTML 而已。

revalidate

revalidategetStaticProps 的一个选择性参数,它可以用来决定一个页面多久会重新打包一次。

export async function getStaticProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  return {
    props: {},
    revalidate: 60,
  }
}

以下是一个 revalidate 设定为 60 秒的示范图:


*https://vercel.com/docs/next.js/incremental-static-regeneration*

revalidate: 60 的意思是说页面会 60 秒後就会失去 cache 的作用,Next.js 必须为这个页面重新打包一次,但是如果没有使用者浏览这个页面的话,Next.js 也不会主动重新打包这个页面。

而这个设定实际上运作的方式如下:

  1. 60 秒以前:这时不论跟服务器请求几次这个页面,都会回应同样的 HTML 给使用者
  2. 60 秒以後:当使用者浏览页面时看到的仍然是旧的内容,但是服务器发现这个页面已经不再被 cache,所以会重新执行 getStaticProps ,进行重新打包的流程。在打包完成之後,Next.js 会更新 cache,并且当有使用者浏览该页面时,看到的都会是新的内容。

revalidate: 60 作为范例,Next.js 会修改 header 中的 Cache-Control 数值, s-maxage 会等於 revalidate 设定的数值。

Cache-Control: s-maxage=60, stale-while-revalidate

怎麽选择 fallback

要使用 Incremental Static Regeneration 这个功能, 在 getStaticPaths 中的 fallback 就必须是 true'blocking' 其中一种,对於使用者来说两个的体验差别是有没有 fallback page, 设定fallback: true 能够用 isFallback 判别目前的 fallback 阶段,并回传 loading 的特效或是其他的 component 给使用者,而设定 'blocking' 则没有 fallback page,更像是 SSR 的体验,使用者会等待页面生成完毕後,直接看到完整的网页内容。

两者看起来很相似,怎麽选择呢?

fallback: true v.s. fallback: 'blocking'

  • 'blocking'官方推荐使用这个参数,原因虽然没有说,但是在 Next.js 的 GitHub issue 中翻了一会儿,会发现 'blocking' 的好处是有利於 SEO,虽然对於会执行 JavaScript 的 Google 爬虫没有影响,但是像是 Facebook 或 Twitter 等不会执行 JavaScript 的爬虫, 'blocking' 才能确保爬虫拿到的资料是完整的。
  • true : 如上述,因为 true 会使爬虫看到的是 fallback page,如果没有执行 JavaScript,则无法拿到更新後的内容,如此对於 SEO 不利。但是,对於需要经过 authentication 的页面或是後台页面来说,也许 true 是一个好的选择,因为不用在意 SEO,而且透过 web skeleton 可以让使用者更快地看到网页预载入的内容框,从另一个面向来看是可以优化 UX 的选择。

小结

在这篇文章中,我们谈到了 Next.js 的 Incremental Static Regeneration 这项重要的功能,它能够帮助我们降低打包时间,在使用者请求页面时才动态地生成页面。

此外,我们还了解到如何使用 revalidate 设定重新生成页面的时间,并且 Next.js 还会自动更新 cahce;以及了解 fallbacktrue'blocking' 的优缺点,也知道使用这两个参数的时间点。

Reference


<<:  Day 11基础元件

>>:  Day9_HTML语法6

Day26 Data Storage in iOS 02 - Keychain & Property list (Plists)

Keychain Apple Keychain 是一个非常流行且功能强大的 Swift 工具,每个 ...

【Day 9】设置虚拟主机 EC2 x 吴念真的土豆神器

tags: 铁人赛 AWS EC2 闲话家常 历久不衰的虚拟机器 开赛以来发现大家都用很新很潮的技术...

新新新手阅读 Angular 文件 - Interpolation(2) - Day14

文章内容 本章内容为阅读官方文件有关 interpolation 的笔记内容。 Expression...

认识HTML(七):表单栏位(上)

表单input元素 一般表单中所看到的输入栏位,可以用 <INPUT> 元件与其属性ty...

[Vue.js] 基本语法

(以下文章适用於Vue.js 2.X版本) Vue.js 官方手册 起手式 引入 Vue.js ne...