iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
Modern Web

Nuxt 3 學習筆記系列 第 28

[Day 28] Nuxt 3 渲染模式 (Rendering modes) 與網站使用體驗核心指標 (Core Web Vitals)

  • 分享至 

  • xImage
  •  

前言

Nuxt 3 作為一個完整的全端框架,也兼具了開箱即用的特性,當你選擇 Nuxt 3 開發網站準備建構正式環境的專案時,可以根據使用方式與解決情境,選擇是否啟用伺服器端渲染 (SSR),或單純的產生靜態頁面做 SSG,而這篇主要講述的是 Nuxt 3 所提供的渲染模式以及如何進行選擇。

Nuxt 3 的渲染模式

根據官方文件的介紹,Nuxt 3 目前支援的渲染模式包含僅在客戶端渲染 (Client-side Only Rendering)通用渲染 (Universal Rendering),在本系列的文章的也有稍微提到。

通用渲染 (Universal Rendering)

Nuxt 3 預設的渲染模式是通用渲染 (Universal Rendering),這個設定是依據 nuxt.config.ts 中的 ssr 屬性做調整,預設為 true

export default defineNuxtConfig({
  ssr: true
})

也就是說,當建立一個 Nuxt 3 新專案,預設就是 SSR 的渲染模式。

僅在客戶端渲染 (Client-side Only Rendering)

如果我們想要關閉 SSR,只在客戶端進行渲染,可以將 nuxt.config.ts 中的 ssr 屬性設為false
整個專案在就建構後,就如同 Vue 建立出來的網站,除了首頁的容器頁面,畫面的渲染與響應操作,都會在客戶端完成。

Nuxt 3 的靜態頁面生成 (Static Site Generation, SSG)

Nuxt 3 在 v3.0.0-rc.10 版本,實現了全靜態生成 (Full Static Generation),才終於有了完全靜態,不然更早版本以前可能以為的靜態頁面,發生需要打 API 或許資料的情況。

透過 Nuxt 產生的靜態頁面,會在建構階段將所有 .vue 頁面所需要的 JS、樣式或檔案等進行組織與預渲染(pre-rendering),最重要的是將頁面或元件內需要透過API 請求資料的地方,一併在建構時取得這些資料,並添加進各自的 HTML 頁面與對應的 Payload 內。

所以說全靜態頁面的網站,可以直接部署至任何靜態託管服務,例如 Netlify、GitHub pages 或 Vercel 等,不再需要自己處理或架設 Node.js 伺服器也不依賴 API Server;由於是靜態的 HTML,SSG 很適合做內容不會有太常變化的靜態網站,對於 SEO 的搜尋引擎爬蟲解析或 CDN 快取頁面來提昇網站效能都是非常友善的。

Nuxt 3 的混合渲染(Hybrid Rendering)

如果我們在建構網站時,想將部分頁面產生為靜態的網頁,而其他則保留 SSR 來動態的獲取資料進行渲染,這種情境我們可以使用 nitro.prerender.routes 手動設定預渲染的路由。Nuxt 3 在未來將提供一種名為混合渲染(Hybrid Rendering) 的模式,來增進各個路由頁面所需要的渲染策略。

混合渲染模式,其概念就是允許每個路由能有不同的渲染策略,例如,文章的瀏覽想以靜態頁面產生,管理後台只需要客戶端渲染,只需要透過指定路由及設定屬性,就能在建構時自動完成這些自訂的策略而生成頁面。

Nuxt 官方預期在 nuxt.config 提供一個 routeRules 來設定不同頁面的渲染策略,範例如下:

export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },         // 每一次建構時,都重新預渲染頁面 (透過 Builder)
    '/blog/**': { static: true },      // 接收到一個請求時,頁面依照需求重新渲染頁面 (透過 Lambda)
    '/products/**': { swr: 600 },    // 接收到一個請求時,10 分鐘的快取緩衝過期後,將會再次的重新取得資料進行渲染 (透過 Lambda)
    '/admin/**': { ssr: false },       // 僅在客戶端渲染
    '/react/*': { redirect: '/vue' }, // 路由重新導向規則
    '/api/**': { cors: true },        // 添加 CORS Header
  }
})

如此一來在建構網站時,就能依據不同的路由渲染策略來自動生成網頁。

網站使用體驗核心指標 (Core Web Vitals)

Web Vitals 是 Google 開創的一項計畫,主要以優化使用者體驗為目標,其中 Core Web Vitals 共有三項指標來評估使用者體驗,測量的指標會依據時間的發展可能有所不同,Google 目前依照構成使用者體驗的三個面向——載入速度、可互動性和視覺穩定性來衡量,這三個面向分別對應下列三項指標,以下稍微簡述一下,有興趣可以至 web.dev 中觀看更詳細的說明。

最大內容繪製 (Largest Contentful Paint, LCP)

最大內容繪製 (LCP),主要用以衡量網頁的載入速度,當進入一個網站時,網頁會開始載入文字、圖片等,並開始繪製畫面中的元素,當可視區域不再有新的更大的元素載入後,LCP 時間才至此為止。也就是說使用者若等待畫面中的較大區塊的圖片載入時間過長,容易導致體驗不佳。LCP 的時間建議為開始載入後的 2.5 秒內。

https://ithelp.ithome.com.tw/upload/images/20221013/20152617H8TYpsMKlk.png

首次輸入延遲 (First Input Delay, FID)

首次輸入延遲 (FID),主要用以橫衡量使用者能在網站上進行操作的時間,也稱為網站可進行互動的時間,例如,使用者點擊連結、點擊按鈕而驅動了 JS 的操作事件,這項操作直到瀏覽器做出回應,並能實際的處理事件所經過的時間稱之為 FID,為了良好的使用者體驗,建議將 FID 時間控制在 100 毫秒以內。

https://ithelp.ithome.com.tw/upload/images/20221013/20152617rcxI38qCFN.png

累計布局排版偏移 (Cumulative Layout Shift, CLS)

累計布局排版偏移 (CLS),試想當使用者於網頁上點擊了一個按鈕或其他物件,因為某些原因跳出了新的元素導致點擊的按鈕被擠壓到,造成在網頁上的位置發生位移,進而導致使用者誤觸或點擊到非預期的位置觸發其他事件,這會造成使用者體驗不佳,因此網頁的布局排版的穩定性也就是視覺穩定性,應控制在位移比例低於 0.1,而這個 CLS 數值計算的公式為 影響分數 * 距離分數,細節可以參考這裡

https://ithelp.ithome.com.tw/upload/images/20221013/20152617Luf73r9Ij3.png

Nuxt 3 渲染模式與網站使用體驗核心指標

網站使用體驗核心指標其中的 LCPFID 指標,與 Nuxt 3 的渲染模式的選擇最為相關,我們選擇 SSR 不光只是為了解決 SEO 的問題,還需要考量使用者的體驗。

例如,我們選擇了通用渲染來製作 SSR 與 SPA,既解決了 SEO 也提升了使用者體驗,網頁第一次就完整的顯示出來,但實際上在 Vue 的 JS 載入之前,網站是不具有互動性的,直至 Hydration 步驟完成,我們才能操作網頁上的元件。選擇渲染的方式同時也引發了首次內容繪製 (FCP)可互動時間 (TTI) 問題,而 LCP 與 FID 也通常發生在這之間。

所以說,不是 SSR + SPA 就是萬用解,我們仍有 SSG、ISR 等渲染方式來因應各個情境,而 Nuxt 3 也幫我們應付與解決多數可能遇到的使用情境及痛點,更多網站使用體驗核心指標細節與優化可以再參考網路上的資訊,最後可以在依據需求及使用情境來調整各個頁面或整個網站的渲染方式。

小結

Nuxt 3 混合渲染模式期待以路由的方式來表示緩存或渲染的規則,因此能更具有彈性且能以 SWR 與 ISR 解決單純的 SSG 所面臨的痛點,此外選擇網站的渲染模式除了依據使用情境外也可以參考網站使用體驗核心指標 (Core Web Vitals) 來配置渲染的規則,讓使用者也能擁有最佳的使用體驗。


感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。

參考資料


上一篇
[Day 27] Nuxt 3 測試 (Testing) 與錯誤處理 (Error handling)
下一篇
[Day 29] Nuxt 3 發布網站前的建構打包 (Build) 與靜態網站生成 (Static Site Generation)
系列文
Nuxt 3 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言