iT邦幫忙

2024 iThome 鐵人賽

DAY 29
1
JavaScript

Vue.js學習中的細節陷阱:30天自我學習指南系列 第 29

Day 29: Vue 的不同渲染模式 - CSR、SSR和通用渲染模式

  • 分享至 

  • xImage
  •  

Vue可以用來構建單頁應用程式 (SPA),打包後的程式碼會完全在瀏覽器上執行,透過 JavaScript 生成 DOM 元素並交由瀏覽器進行呈現(Client Side Rendering, CSR)。不過,Vue 的程式碼同樣可以在 Node.js等其他 JavaScript 執行環境中運行,將創建元件模板等工作交由伺服器處理,實現伺服器端渲染 (Serve Side Rendering, SSR) ,這樣的設計能夠加快初次渲染速度,並且有助於提升 SEO,也有衍生另一種結合兩種模式並行的通用渲染模式(universal)

在學習完Vue的基本使用知識後~來理解一下CSR和SSR的不同和先備知識吧,也可以對未來進階到使用SSR渲染框架Nuxt等,能夠縮短使用上觀念的誤區。

今日學習目標

  1. 理解客戶端渲染(CSR)、伺服器渲染(SSR)和通用渲染模式
  2. 為什麼有些生命週期鉤子(onMounted)無法在伺服器環境中執行?

客戶端渲染(CSR)、伺服器渲染(SSR)和通用渲染模式

伺服器渲染(Server Side Render, SSR)

要理解伺服器渲染用圖解來說應該會比較快:

  1. 當我們在瀏覽器按下某個網址發出請求
  2. 伺服器接收到請求後因為需要資料,會跟資料庫做連線並進行一些撈取資料操作
  3. 資料庫回傳資料篩選結果給伺服器,通常這段會是非同步。
  4. 伺服器將收到的數據與指定的模板進行結合,生成完整的 HTML。此時,伺服器已經把靜態模板動態數據合併,完成了伺服器端的工作。
  5. 伺服器將渲染好的 HTML 回傳給瀏覽器,瀏覽器接收到後立即進行解析HTML並且要結合一些互動邏輯,最終用戶就能立即看到完整的頁面內容,而不需要等待客戶端再去請求數據和渲染頁。

不過比較大的問題時,每次使用者一些小的互動操作會有類似頁面跳轉重刷,對於使用者體驗來說不是很好。

https://ithelp.ithome.com.tw/upload/images/20241012/2014525168N3EcC6W5.png


客戶端渲染(Client Side Render, CSR)

客戶端渲染和伺服器端渲染差別最大,大致上是在步驟4步驟5的階段:

  • 伺服器回傳資源 (步驟 4)
    伺服器將 HTML 框架、打包好的 JavaScript 和 CSS 資源回傳給瀏覽器。JavaScript 通常是以 bundle 的形式(例如 bundle.js 或分割好的 chunk.js),用於在瀏覽器端生成和渲染虛擬 DOM 結構

  • 瀏覽器執行 JavaScript (步驟 5)
    瀏覽器接收 HTML 和 bundle 檔案後,先渲染出一個空白頁面,然後開始執行 JavaScript 程式碼。
    JavaScript 程式碼會根據初始資料和應用邏輯生成虛擬 DOM(Vue App實例初始化過程),並透過 JavaScript 將虛擬 DOM 與真實 DOM 結合並進行渲染,最終產生可互動的使用介面,等於說產生樣板的工作交由瀏覽器來負責~

https://ithelp.ithome.com.tw/upload/images/20241012/201452510y8bO3qrII.png


通用渲染模式

CSR和SSR渲染模式各有優缺點,便衍生出通用渲染模式將兩種運行在同一個應用程式裡面:

通用渲染模式(Universal Rendering),也有人稱為 同構渲染(Isomorphic Rendering) ,指的是在前端框架中,程式碼可以在伺服器端和客戶端同時執行並生成相同的 HTML。 可以結合SSR提升SEO和加快首屏渲染速度優點以及CSR使用者在互動上更好的體驗。

像Vue的衍生SSR框架Nuxt,預設模式是通用渲染模式 :

瀏覽在第一次下載完 HTML 文件後,會在後台載入並執行伺服器端生成的 JavaScript 程式碼(主要是生成樣板template)。 之後交由瀏覽器會解析這些程式碼,接著由 Vue.js 接管文件並啟用互動功能,因此稱為通用渲染。

水合(hydration)

水合是指瀏覽器將伺服器生成好的靜態HTML檔案在客戶端上被解析後,和JavaScript的互動功能進行結合的過程。這個過程會把渲染好的靜態DOM元素「激活」,並加上事件監聽器等交互功能,使它們變得可互動。

水合其實也可以做滿多進階優化,像是階段性水合(Progressive Hydration)等,將網頁分區塊水合而不是整頁一起執行水合-衍伸文章

https://ithelp.ithome.com.tw/upload/images/20241012/20145251K5VB6BQSkd.png

實際上網頁的渲染模式還有滿多的,有莫大大的文章寫得滿詳細的:

  • 靜態生成(Static Site Generation ,SSG)
    網站構建(build)階段,預先將每個頁面渲染成靜態 HTML 文件。這些靜態頁面然後直接部署到CDN上,當用戶訪問網站時,瀏覽器從 CDN 快取下載並顯示靜態頁面,速度會比一般伺服器渲染回應還快。
    但顯著缺點是每次內容更新需要重新構建整個網站,這對於內容更新頻繁的網站來說構建流程可能會很耗時。

  • 增量生成(Incremental Site Rendering, ISR)
    增量生成是在靜態生成的基礎上進行改進,允許網站在初次生成靜態頁面後,可以設定特定的重新生成間隔時間或基於請求的增量更新。這樣可以實現靜態網站的局部更新,而不必重新構建整個網站。
    例如: 可以設定特定的頁面更新時間(每10分鐘更新一次),或基於流量請求增量生成新內容,設定上需要額外參數去設定,操作上比較複雜。


為什麼有些生命週期鉤子無法在伺服器環境中執行?

這是最近公司碰到某些需要SEO的專案,前端工程師們需要以Nuxt去作開發,想說不就是原有Vue學到的觀念,直接移植過去XD,然後發現又不太一樣,啟動SSR渲染模式或混合模式Vue的生命週期鉤子(Lifecylce hook)不會全部都在伺服器端執行?

這是一開始使用SSR框架中混合模式比較容易搞混的,因為 JavaScript 執行環境變成兩種: 瀏覽器伺服器,有些瀏覽器或Vue提供的API,本身是專屬於瀏覽器端執行的~

負責Virtual DOM樣板構建和瀏染器渲染 - 兩階段工作的拆分

如果以上面的伺服器渲染(SSR)負責的工作去思考的話,會比較容易理解為什麼有這個問題,SSR其實是把樣板製作工作放到伺服器中來執行。

要產生樣板會利用到我們先前 Day 2: Vue SFC樣板(Template)和渲染函式(Render Function) 提到的渲染函式來製作。 它本身產出來的產物是一段類似巢狀的,描述節點特徵的 JavaScript 物件,之後可以構建出完整 Virtual DOM。

在compostion API 中可以使用<setup script>將樣板資料和template編譯進去,options API 則是來保有 createdbeforeCreated 這兩個Vue的生命週期鉤子,可以正常在Nuxt伺服器端使用。

不過,若是牽涉到瀏覽器初次掛載或更新瀏覽器DOM的操作(Runtime core API),像是onMounted或是onUpdated等,元件卸載相關的操作unMounted也是,本身操作會跟瀏覽器端提供的API相關,就沒辦法在Nuxt伺服器端看到它的運行囉~

-伺服器端無法執行瀏覽器專屬操作
localStoragesessionStoragewindow.location 等屬於瀏覽器 API 的功能只能在客戶端使用,如果嘗試在伺服器端使用這些 API,會導致錯誤,因為它們在伺服器端並不存在,也是一樣原理。

https://ithelp.ithome.com.tw/upload/images/20241012/201452519qehtXSElE.png


總結

今天理解 CSR、SSR 和通用渲染模式他們的工作流程,可以簡單歸納一下:

  • CSR(客戶端渲染)
    完全在瀏覽器端生成和渲染頁面,互動性強,但首屏渲染速度慢,對 SEO 不利。

  • SSR(伺服器渲染)
    在伺服器端生成 HTML 並將其發送到客戶端,有較好的首屏渲染速度和 SEO 表現,但每次需要伺服器渲染頁面時會重新載入,影響用戶體驗。

  • 通用渲染模式(Universal Rendering)
    結合 SSR 和 CSR 的優點,先在伺服器生成 HTML,然後在客戶端水合,使頁面具備互動性,提升用戶體驗。這模式在 Nuxt 中廣泛應用。

但是在使用混合模式對新接觸伺服器渲染(SSR)的工程師,是比較容易困惑,因為有兩種執行環境上的差異,導致我們開發時要先區分和理解Vue和Nuxt所開發出來的API,它們負責的工作和執行環境階段

onMounted 等瀏覽器專屬的生命周期鉤子無法在伺服器端執行,這是因為它們依賴於瀏覽器 API的功能。了解這些差異能幫助開發者更好地在不同的渲染模式中進行開發和除錯。


學習資源

  1. https://mokkapps.de/vue-tips/differentiate-client-and-server-components-in-nuxt
  2. https://www.shubo.io/rendering-patterns/
  3. https://ithelp.ithome.com.tw/articles/10279519
  4. https://www.shubo.io/rendering-patterns/
  5. https://juejin.cn/post/7115646231640014885
  6. https://enterprisevue.dev/blog/vue-3-lifecycle-hooks-explained/
  7. https://vuejs.org/guide/scaling-up/ssr.html#reactivity-on-the-server

上一篇
Day 28: Vue 的元件更新優化-重新渲染問題 (Re-render)
下一篇
Day 30: 完賽 - Vue 的 30天自我學習旅程回顧
系列文
Vue.js學習中的細節陷阱:30天自我學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言