VueSSR高階指南

吳俊毅發表於2018-09-04

嗨 各位小夥伴好,好久沒有寫文章了,這次分享一下我們從使用node以來,前端架構上的一些優化 如果看過我上一篇文章B站的前端之路的小夥伴可能知道 我們從去年開始打烊 使用node 到現在已經經歷了一年的迭代,承載的訪問量也從百萬級別 擴大到了現在的億級別,這次補充一些乾貨吧~

vue如何實現熱更新

我們都知道,對於node來說,前端vue程式碼的迭代節奏是很快的,可能一週要迭代幾次,但是node的迭代卻沒那麼平凡,可能一週更新一次甚至更久,那麼為了node服務的穩定,減少node服務的釋出次數,是非常有用的。 配置中心是肯定需要的,因為需要通過配置不同的資源版本號,來通知node服務更新服務上的版本號 那麼 我們的vue程式碼 要如何改造才能實現熱更新呢? 我們就以vue官方給的例子來看
以下程式碼是我擷取的兩段程式碼官方案例:
首先他定義了一個createRenderer的方法
裡面呼叫的是vue-ssr的createBundleRender方法來建立的渲染函式

VueSSR高階指南
然後傳入了使用了三個檔案,template.html bundle.json 和clientmanifest.json
VueSSR高階指南
這裡可以看到 在createRender的時候 傳入的clientMainfest bundle 都是reqire的 那麼有同學會想,我要支援熱更新 是不是根據require的快取機制,去定時的清理快取?雖然也能實現但是其實不用的 我查詢了官方的api文件,其實bundle支援三種引數
VueSSR高階指南
然後再看下vue的原始碼,如果傳入的是一個絕對路徑,類似於上面這個案例 require某個dist目錄下的bundle.json檔案的時候 做了什麼處理
VueSSR高階指南
它判斷 如果是一個js 或者json檔案路徑的 那麼 他會先讀取這個檔案,然後通過json轉化一下成物件,然後再走下面的判斷是否是oject邏輯 那麼,我們不是可以替他做這個事情嘛 我們可以從遠端讀取到bundle檔案 然後將他轉化成bundle 然後傳入給createBundleRender方法 就可以不用通過require方法去獲取了 然後遠端bundle檔案加上版本號,就可以實現通過配置來熱更新

vue專案與node專案分離

為了前後端分離,我們在前端和api層中間,架構了一層node層,用來做服務端渲染,來加快使用者的首屏可用和對搜尋引擎的友好。專案一開始放置在同一個git倉庫裡面,分別放在client目錄和server目錄中(或者類似於vue 官方例子中的一樣,node服務可能只有一個sever.js。因為server中可能需要client中的一些資源,所以不得不將他們放在一起。後來通過配置中心驅動之後,client 和server 可以完全獨立,通過配置中心建立連線。所以完全可以將client專案和server專案分離開。

VueSSR高階指南
其實就是在前端專案中,再做了一次前後端分離,這次分離的原因 跟與api的前後端分離有些不一樣。這次是因為 第一個 前端vue專案本就是一個完全獨立的專案,拖著server專案反而顯的不是那麼靈活,同樣,server裡面包含了client,雖然可以獨立釋出,但是因為迭代週期的不同,在管理分支上面總歸有點變扭,索性分開,各過各的 各過各的是極好的,可是開發的時候怎麼各過各的啊(f***~),我開發的時候要走服務端渲染的邏輯的啊,你讓我先基於客戶端開發,然後再配合著node除錯一波?那可不是反而增加了開發成本 有沒有可以讓client獨立也能跑ssr的邏輯,然後最後只要跟正式的node服務通過配置中心配合起來就好了呢? 有啊,給client配置一個簡單的服務不就好了麼?一般的nodessr不都是這樣的麼 說白了就我上面說的,一個sever.js。裡面是一個基於koa的簡單服務,加上了koawepack的中介軟體(koa-webpack),用來做開發時候的熱載入。 然後通過不同的啟動指令碼,來配置上不同的環境變數引數,以此來啟動不同的頁面開發,這樣子,開發就方便多了,npm run start:home 就是開發首頁,npm run start:video 就是開發播放頁 後面加上server引數就是開發服務端渲染 例如 npm run start:home:server (這裡我只提供一個思路昂~具體實現要講的東西太多了,這裡不太想寫 >_>~~)

容災

既然是個node服務,那麼對於服務也要有相應的容災方案,不然怎麼放心將大流量交給它 那麼,我們需要一個降級方案以備不時之需(以下內容需要建立在你對vuessr有一定了解的基礎之上) 首先 vue 服務端渲染都有兩個入口檔案,entryclient.js和entryserver.js 如果要支援降級,那麼需要在entryclient.js上面動一些手腳,我們仍然以官方例子為例 現在index.temlate.html 增加一個客戶端渲染容器,一個名為de-app的div(<!--vue-ssr-outlet-->是服務端渲染的佔位符)

VueSSR高階指南
然後,我們看一下entryclient.js裡面
VueSSR高階指南
這裡是用來同步服務端資料到客戶端store裡面的,那麼,如果降級到客戶端渲染,這裡就需要做一下相容
VueSSR高階指南
我們預設服務端渲染一定會有window.__INITIAL_STATE__,如果沒有 說明服務端沒有幫我們取到資料,也就是降級到了客戶端渲染,那麼需要重新執行以下asyncData方法來從客戶端獲取一下資料,然後掛載到我們預先設定好的de-app上面,當然 原本掛載到app上的 也要做一下判斷了
VueSSR高階指南
這樣子,服務端如果沒有渲染出內容來,那麼,頁面還是可以通過客戶端渲染,重新走一遍邏輯,正常輸出頁面來。 vue程式碼改完了,我們在構建的時候,也要以兩種目的去打包我們的html,一種是純粹的模版html(template.html),裡面除了一些固定的js引入外,沒有vue打包相關的js引入,是用來給服務端渲染當作模版用的(就是上面說的傳遞給createBundleRender的),另一個打包將構建好的js css引入進去了(degrage.html),可以直接當客戶端渲染的靜態模版使用 (就是使用兩次htmlwebpackplugin 一個傳chunks 一個不傳)
VueSSR高階指南
那麼具體怎麼使用這兩個檔案呢? 我們準備了三層降級
VueSSR高階指南

  • 1.首先 node服務上面,自己起了一個服務,用來監測所有的node程式的cpu使用率是否大於設定的閾值,如果超過設定閾值,那麼返回我們事先準備好的degrade.html檔案,降級掉服務端渲染,可以大大減少服務端的渲染壓力,當然也可以手動設定是否需要降級嘛,來去自如
  • 2.如果Node不幸 炸了,那麼 需要在slb 這一層上 也就是nginx 做一個配置,如果服務返回的code是5xx,那麼將流量指向我們實現釋出好的degrade.html
  • 3.如果非常不幸,全炸了,那麼如果頁面配置了cdn快取,cdn回源失敗,就返回之前快取上的頁面
    那麼在極端情況下,其實還是會有首屏頁面展示給使用者的(資料兜底會讓這個方案更完美,下次有機會再補上吧)
    這次就這麼多吧,下次可能會補充上一些別的優化和react的一些黑科技~

嗶哩嗶哩 乾杯~

相關文章