Next.js App Router 後 Caching 的一些思路

date
Jan 31, 2024
slug
caching-for-next-js-app-router
status
Published
tags
Frontend
Next.JS
summary
type
Post
這篇所指的 Cache 是 CDN Cache,Next.js 的 incremental cache (Full Route Cache, Data Cache) 相關介紹可以看這篇 → https://blog.maxam.dev/next-js-incremental-static-regeneration
Next.js 在 App Router 後,頁面如何 cache 會藉由以下幾點來決定
  • 是否有使用到 Dynamic Function (headers(), cookies(), searchParams)
  • page / layout 的 dynamic / dynamicParams / revalidate / fetchCache prop
  • 是否在 fetch 時戴上 cache: no-cache
而仔細注意可以發現這幾點是 build time 就可以決定好的,因此靜態分析就可以得出頁面本身是 Static Route 還是 Dynamic Route。
🪄
Static Route 會有 Prebuild 的行為。 順帶一提,Prebuild 頁面的行為和瀏覽頁面時一樣,如果 runtime request 進來時會操作到 Data Cache,在 build time 也會有一樣的行為。因此預設使用 disk cache 的情況下,在 build 時就有可能操作到 .next/cache/fetch-cache,因此如果有拿 build cache 的話需要注意這點。

預設的 Cache Control

  • 靜態頁面 Static Route
    • s-maxage=..., stale-while-revalidate
    • max age 值會選用頁面中最小的 revalidate 值
    • ⚠️
      Next.js 自帶的 cache-control 中 stale-while-revalidate 本身沒帶 delta time,蠻多 CDN 不吃這個格式的 (ex. Cloudflare, CloudFront),詳見 https://github.com/vercel/next.js/issues/51823
  • 動態頁面 Dynamic Route
    • private, no-cache, no-store, max-age=0, must-revalidate

動態改動 Cache Control

那麼我們有機會改動 Cache Control 嗎?答案是可行的,但只能在 middleware 處理,這算是 Streaming HTML 的痛點,在 Page 層無法處理 HTTP Header。
一個簡單針對訪客 (未登入) 流量寫入 Cache Control 的 middleware 範例
⚠️
上面的寫法還有些需要考量的點,因爲 middleware 層執行的時間點在 page 之前,雖然能成功寫入 cache-control,但無法知道頁面是否能正常顯示 (HTTP status < 300)。可能還需要研究一下要如何配合 Next.js 的 notFound() or error boundary
 

Cache 後衍伸的問題

這個問題和上新版本有關,傳統在處理新舊版本時避免混在一起,會使用 cache busting 或 file hashing 讓 js filename 不同,而 Cache HTML 本身會讓舊版本停留的時間變更久,為了讓上新版本後可以正確拿到 js file,也該將 js file 放到 CDN 上。
上述的問題聽起來都有解法,但在 App Router 上我們又多了一個新的情境 —— React Server Component (RSC)。
在頁面跳轉時,App Router 會藉由 HTTP request 拿取 wire format 並渲染到畫面上,而單一台主機在上版後,會是新版本的 Server,因此針對舊版的 RSC request 處理上可能會有非預期的結果;即使多 pod 的情形可以保存多個不同版本,在 forwarding 上也得做處理。而這個問題有個專有名詞叫做「Version Skew」。
⚠️
Version Skew 這個問題本身和 Public Cache 無關。沒 Cache 的情形下,只要升版也有可能遇到,只是 Cache 拉長會讓這個情形更明顯而已
而針對這題 Vercel 本身有處理,所以如果你使用他們的服務就不用擔心了,他們也有寫一篇 https://vercel.com/blog/version-skew-protection 提供了如何解決的一些思路,但這塊對於 Self Host 上真的增加了不少難度 💩
 

© maxam 2023 - 2024