Vue.js SSR 編寫通用代碼

2021-01-07 16:00 更新

在進一步介紹之前,讓我們花點時間來討論編寫"通用"代碼時的約束條件 - 即運行在服務器和客戶端的代碼。由于用例和平臺 API 的差異,當運行在不同環(huán)境中時,我們的代碼將不會完全相同。所以這里我們將會闡述你需要理解的關鍵事項。

服務器上的數據響應

在純客戶端應用程序 (client-only app) 中,每個用戶會在他們各自的瀏覽器中使用新的應用程序實例。對于服務器端渲染,我們也希望如此:每個請求應該都是全新的、獨立的應用程序實例,以便不會有交叉請求造成的狀態(tài)污染 (cross-request state pollution)。

因為實際的渲染過程需要確定性,所以我們也將在服務器上“預取”數據 ("pre-fetching" data) - 這意味著在我們開始渲染時,我們的應用程序就已經解析完成其狀態(tài)。也就是說,將數據進行響應式的過程在服務器上是多余的,所以默認情況下禁用。禁用響應式數據,還可以避免將「數據」轉換為「響應式對象」的性能開銷。

組件生命周期鉤子函數

由于沒有動態(tài)更新,所有的生命周期鉤子函數中,只有 beforeCreatecreated 會在服務器端渲染 (SSR) 過程中被調用。這就是說任何其他生命周期鉤子函數中的代碼(例如 beforeMountmounted),只會在客戶端執(zhí)行。

此外還需要注意的是,你應該避免在 beforeCreatecreated 生命周期時產生全局副作用的代碼,例如在其中使用 setInterval 設置 timer。在純客戶端 (client-side only) 的代碼中,我們可以設置一個 timer,然后在 beforeDestroydestroyed 生命周期時將其銷毀。但是,由于在 SSR 期間并不會調用銷毀鉤子函數,所以 timer 將永遠保留下來。為了避免這種情況,請將副作用代碼移動到 beforeMountmounted 生命周期中。

訪問特定平臺(Platform-Specific) API

通用代碼不可接受特定平臺的 API,因此如果你的代碼中,直接使用了像 windowdocument,這種僅瀏覽器可用的全局變量,則會在 Node.js 中執(zhí)行時拋出錯誤,反之也是如此。

對于共享于服務器和客戶端,但用于不同平臺 API 的任務(task),建議將平臺特定實現包含在通用 API 中,或者使用為你執(zhí)行此操作的 library。例如,axios 是一個 HTTP 客戶端,可以向服務器和客戶端都暴露相同的 API。

對于僅瀏覽器可用的 API,通常方式是,在「純客戶端 (client-only)」的生命周期鉤子函數中惰性訪問 (lazily access) 它們。

請注意,考慮到如果第三方 library 不是以上面的通用用法編寫,則將其集成到服務器渲染的應用程序中,可能會很棘手。你可能要通過模擬 (mock) 一些全局變量來使其正常運行,但這只是 hack 的做法,并且可能會干擾到其他 library 的環(huán)境檢測代碼。

自定義指令

大多數自定義指令直接操作 DOM,因此會在服務器端渲染 (SSR) 過程中導致錯誤。有兩種方法可以解決這個問題:

  1. 推薦使用組件作為抽象機制,并運行在「虛擬 DOM 層級(Virtual-DOM level)」(例如,使用渲染函數(render function))。

  1. 如果你有一個自定義指令,但是不是很容易替換為組件,則可以在創(chuàng)建服務器 renderer 時,使用 directives 選項所提供"服務器端版本(server-side version)"。
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號