【前端新手日記】網頁渲染模式 - SSG、ISR

之前已經看過了 CSR 和 SSR 這兩種渲染模式了,今天再我們從回顧什麼是 SSR 開始來看 SSG 和 ISR 這兩種網頁渲染模式。

回顧 SSR 
SSR 指的是「伺服器端渲染 (Server-Side Rendering)」,也就是說渲染 HTML 的這件事情是交由伺服器來處理,所以瀏覽器在發送 request 後,得到的 response 會是完整頁面的 HTML 檔案。SSR 有分舊時代的 SSR 和新時代的 SSR,舊時代的 SSR 就是很單純的一個概念,那就是前面所提到的「發送 request 後,由伺服器回完整頁面的  HTML 及相關的 CSS 給瀏覽器,每次進行互動的動作時,例如:送出表單,都會重新經歷一次這個發送 request,在次取得一份新的 HTML 的動作」。但在新時代的 SSR 中,則是優化了每次做一個操作動作,就要重新發送 request 去得新的 HTML 的部分,只會在第一次進到頁面時,才進行發送 request 取得完整 HTML 及相關的 CSS 等靜態檔案的 response,在這之後的操作、互動動作,會因為 Javascript 有被綁定在 DOM 元素上(hydration),而可以在不特別向伺服器請求新的 HTML 等靜態檔案的狀態下,就讓畫面呈現操作的效果。

新時代的 SSR 是為了解決舊時代的 SSR 每次做一個操作都要重新等待完整的 HTML 回來的缺點,但又保持著第一次進入頁面時就可以拿到完整的 HTML 頁面,以維持有助於 SEO 的優點。 


什麼是 SSG ?
前面回顧過 SSR 是什麼之後,緊接著來看一下什麼 SSG。
所謂的 SSG 指的是 「靜態網頁生成 (Static Site Generation)」,簡單來說就是一個在 npm run build 的時候就已經產生的「靜態網站檔案」,有別於 SSR 這個渲染模式,要在發送  request 後,才產生 HTML 檔案,是在 build 的時候就產生,所以可以 cache 在 CDN 上。

這裡也實際從 run build 後的檔案觀察,產生的檔案有什麼差異。 
我用 Next.js 建了兩個 /new 的 index 檔案,左邊使用的渲染模式是 SSR ,右邊使用的渲染模式是 SSG。
【前端新手日記】網頁渲染模式 - SSG、ISR

當執行 npm run build 之後,可以看到 SSR 的模式下,並沒有產生 new 的 HTML 檔案,SSG 模式下,則有產生出一個 new 的 HTML 檔案,這部分就如同前面所提到的一樣,「SSG 與 SSR 不同的地方在於 SSG 在 build 的時候,就會產生 HTML 檔案,不需要在發送 request 時,才透過 server 產生 HTML 檔案給瀏覽器」。

【前端新手日記】網頁渲染模式 - SSG、ISR

從前面提到的特性應該不難了解到 SSG 的優點是利於維持 SEO ,並且有較好效能,不過由於每次內容有更新,都要重新 build 一次檔案,也就比較不適合資料會頻繁有變動的頁面,因此這種形態的渲染方式,會比較很適合大多時候都不會有更新的靜態頁面,例如:部落格、公司介紹頁面。

但是偶爾還是會有一些使用情境是雖然不會有頻繁的資料變動,但卻有要定期更新資料的需求,這時候雖然還是可以用 SSG,但是每次都要重 build 還是很費時及費工,這種時候就可以考慮使用另一種渲染模式。

帶有 SSG 優點並補強 SSG 缺點的 ISR
ISR 指的是「增量靜態生成 (Incremental Static Regeneration)」。簡單來說的話,就是維持 SSG 在 build 的時候就產生靜態 HTML 檔案的優點,但帶有不需要透過 build 來更新頁面的特點。當使用者發送 request 去取得 SSG 的頁面時,會去確認這個頁面是否已經過期,如果沒有過期,會 response 回舊的檔案,如果過期,會在背景進行重新生成新靜態檔案的動作,此時若還沒產生好,會先返回舊的檔案,下次再次進入頁面,則可以取得新產生的檔案。這樣帶有靜態頁面特性,及特定時間自動更新產生新靜態頁面的彈性,讓 SSG 很適合一些需要定期更新,但不需要即時更新的頁面,例如:新聞文章頁面、活動頁面。

接下來一樣用範例來看看有什麼差異,在這個範例中,也是使用 Next.js 寫一個使用 ISR 的 /new 的 index 檔案,這裡有使用 revalidate 來讓網頁可以定期地在不重新 build 的情況下,也能更新頁面。

【前端新手日記】網頁渲染模式 - SSG、ISR

這次特別在 getStaticProps 函式裡面加上一個 console.log 來觀察。
除此之外,我們一樣先 run build 觀察一下 build 完後的檔案,可以發現就如同 SSG 的特性一樣,在 build 的時候,也會產生出 HTML。
【前端新手日記】網頁渲染模式 - SSG、ISR 

另外也透過 console.log 來觀察「頁面過期時,觸發生成新頁面」的動作。
可以發現到當我們第一次進入頁面時,會先顯示一個時間點 (10:54:11),這時候因為頁面還沒有過期,所以沒有觸發 getStaticProps 這個函式,但是再次進入頁面後,因為頁面過期了,就呼叫了 getStaticProps,並在 vscode 的 terminal 內印出時間 (11:02:26),但可以發現到 terminal 印出的時間,與當下的頁面(10:54:11)並不一致,那是因為新的頁面並沒有馬上產生好,所以會先使用舊的頁面,等到再次進入這個網址,才會使用最新的頁面,意即再次進入這個網址才會是
顯示 11:02:26 的頁面。

更進一步觀察 response headers 的話,也可以發現到會有 s-maxage=60 和 stale-while-revalidate=31535940 的設定值內容。
【前端新手日記】網頁渲染模式 - SSG、ISR

 

SSG 和 ISR 的優點和缺點
最後再來回顧一下前面說提到的 SSG 及 ISR 的特點,也思考一下它們各自的優缺點吧!

SSG 有別於 SSR,會在 build 的時候就產生完整的 HTML 靜態檔案,而不需要在發送 request 後,才透過 server 產生靜態檔案,所以如果 SSG 的頁面需要更新,就需要重新再 build 一次,這樣的特性使得 SSG 在內容更新的靈活度上比較差,也因此會比較適合使用在大多數時間都不太需要更新內容的頁面。 

ISR 則是一種 SSG 模式的延伸,它一樣是在 build 的時候,就會產生完整的 HTML 靜態檔案,但是不需要每次都手動 build 一次,而是可以進行一些設定,來決定頁面的過期時間,當頁面過期時,再重新在背景產生新的靜態檔案。因為這樣的特性使得 ISR 適合使用在內容雖然需要更新,但不需要頻繁或即時更新的頁面上。

【前端新手日記】網頁渲染模式 - SSG、ISR

以上就是針對 SSG 及 ISR 進一步認識的部分,打完收工!