Next.JS 的 Incremental Static Regeneration

date
Aug 21, 2023
slug
next-js-incremental-static-regeneration
status
Published
tags
Website
Next.JS
summary
type
Post
ISR 的全名是 Incremental Static Regeneration。與傳統 Server Side Rendering 不同的是中間通過一層 Page Level 的 Cache,如果今天這個頁面已經訪問過就會建立一個 Cache Entry,之後在一定時間內就會只從 Cache 拿資料,可以有效減少 RTT。
除了上述使用者訪問時建立 Cache,NextJS 也提供 Pre-build 的方式,在 Build Time 就可以建立好頁面的 Cache Entry。

Incremental Cache

至於 NextJS 是怎麼實作 Cache 的呢?目前內建兩種方式,一種是存在 Disk 的 File System Cache,而另一個是適用於 Edge Runtime 的 Fetch Cache。詳細的實作可以參考 https://github.com/vercel/next.js/tree/71d424e80477410c374c436f1d7819c53b78bcd5/packages/next/src/server/lib/incremental-cache
 
不過 NextJS 也提供自訂義的 Cache Handler,你可以自己實作一個含 get/set 方法的介面,就可以使用了,使用的方法是從 next config 的 incrementalCacheHandlerPath 注入。
 
⚠️
目前 incrementalCacheHandlerPath 的引入是使用 require,看起來這塊對於 ESM 的支援還待加強。 (2023/08)

Revalidate

這是 ISR 最吸引我的部分,因為多一層 Cache 勢必會有延遲發生,而 ISR 卻提供了 On Demand 以及 Time based 的方式來讓資料過期。前者相當適用於 CMS 類的產品,只要有人在後台更新資料,我們就可以標記對應的 Cache Entry 為過期,下次使用者訪問時就可以觸發 Revalidate 了。
💡
電商網站也相當適用此架構,可達成商家在後台更新商品價格後,能即時在前台呈現最新的價格。

部署

關於部署相關的議題,NextJS 的官方文件上有特別寫一段 Self-Hosting ISR 要做什麼樣的調整。大意是如果今天有多個 pods 的環境,建議共用 Cache,如果是是使用預設的 FileSystemCache,可以選擇 mount persistent volume 到 .next 上。
如果想要客製化地處理 Cache,目前也有兩種方式:

incrementalCacheHandlerPath

如上面所提及,我們可以自行實作 Cache,你可以存在 in memory, disk 或是其他儲存空間 (ex. GCS) 都可以。

SUSPENSE_CACHE_BASEPATH

這是 FetchCache 背後所吃的環境變數 (預設是吃 Vercel 提供的 suspense cache endpoint),目的是給 Edge Runtime 使用的。當然這也可以利用客製化的 incremental cache 做到。

結語

原本敝司的電商網站也想改採用這樣的架構,但和 Architect 們討論後發現在 App Directory 的版本後,ISR 就已經消失了,為了讓後續轉移到 App Dir 更流暢,建議選擇其他方式。
不過這些 Survey 並沒有白費,因為 NextJS 蠻多 Cache 的實作其實都基於他們自己的 incremental cache,像是 App Directory 中能達成共用 Request 的 Fetch、在不使用 Fetch 拿資料時也能緩存資料的 unstable_cache 等都是基於此來實作的。
 

© maxam 2023 - 2024