Vue 專案 SSR 改造實戰

發表於2017-12-20

我們先看“療效”,你可以開啟我的部落格u3xyz.com,通過檢視原始碼來看SSR直出效果。我的部落格已經快上線一年了,但不吹不黑,訪問量非常地小,我也一直在想辦法提升訪問量(包括在sf寫文章,哈哈)。當然,在PC端,搜尋引擎一直都是一個重要的流量來源。這裡就不得不提到SEO。下圖是我的部落格以前在百度的快照:

1460000012440046

細心的朋友會發現,這個快照非常簡單,簡單到幾乎什麼都沒有。這也是沒辦法的事,部落格是基於Vue的SPA頁面,整個專案本來就是一個“空架子”,這個快照從部落格2月份上線以來就一直是上面的樣子,直到最近上線SSR。搜尋引擎蜘蛛每次來抓取你的網站都是一個樣子,慢慢得,它也就不會來了,相應的,網站的權重,排名肯定不會好。到目前為此,我的部落格不用網址進行搜尋都搜不到。在上線了SSR後,再加上一些SEO優化,百度快照終於更新了:

1460000012440047

為什麼要做SSR

文章開始基本已經回答了為什麼要做SSR這個問題,當然,還有另一個原因是SSR概念現在在前端非常火,無奈在實際專案中沒有機會,也只有拿部落格來練手了。下面將詳細介紹本部落格專案SSR全過程。

SSR改造實戰

總的來說SSR改造還是相當容易的。推薦在動手之前,先了解官方文件官方Vue SSR Demo,這會讓我們事半功倍。

1. 構建改造

1460000012440048

上圖是Vue官方的SSR原理介紹圖片。從這張圖片,我們可以知道:我們需要通過Webpack打包生成兩份bundle檔案:

  • Client Bundle,給瀏覽器用。和純Vue前端專案Bundle類似
  • Server Bundle,供服務端SSR使用,一個json檔案

不管你專案先前是什麼樣子,是否是使用vue-cli生成的。都會有這個構建改造過程。在構建改造這裡會用到 vue-server-renderer 庫,這裡要注意的是 vue-server-renderer 版本要與Vue版本一樣。下圖是我的構建檔案目錄:

1460000012440049

  • util.js 提供一些公共方法
  • webpack.base.js是公共的配置
  • webpack.client.js 是生成Client Bundle的配置。核心配置如下:

  • webpack.server.js 是生成Server Bundle的配置,核心配置如下:

2. 程式碼改造

2.1 必須使用VueRouter, Vuex。ajax庫建議使用axios

可能你的專案沒有使用VueRouter或Vuex。但遺憾的是,Vue-SSR必須基於 Vue + VueRouter + Vuex。Vuex官方沒有提,但其實文件和Demo都是基於Vuex。我的部落格以前也沒有用Vuex,但經過一翻折騰後,還是乖乖加上了Vuex。另外,因為程式碼要能同時在瀏覽器和Node.js環境中執行,所以ajax庫建議使用axios這樣的跨平臺庫。

2.2 兩個打包入口(entry),重構app, store, router, 為每個物件增加工廠方法createXXX

每個使用者通過瀏覽器訪問Vue頁面時,都是一個全新的上下文,但在服務端,應用啟動後就一直執行著,處理每個使用者請求的都是在同一個應用上下文中。為了不串資料,需要為每次SSR請求,建立全新的app, store, router

1460000012440050

上圖是我的專案檔案目錄。

  • app.js, 通用的啟動Vue應用程式碼
  • App.vue,Vue應用根元件
  • entry.client.js,瀏覽器環境入口
  • entry.server.js,伺服器環境入口
  • index.html,html模板

再看一下具體實現的核心程式碼:

3. 重構元件獲取資料方式

關於狀態管理,要嚴格遵守Redux思想。建議把應用所有狀態都存於store中,元件使用時再mapState下來,狀態更改嚴格使用action的方式。另一個要提一點的是,action要返回promise。這樣我們就可以使用asyncData方法獲取元件資料了

3. SSR伺服器實現

在完成構建和程式碼改造後,如果一切順利。我們能得到下面的打包檔案:

1460000012440051

這時,我們可以開始實現SSR服務端程式碼了。下面是我部落格SSR實現(基於Koa)

4. 伺服器部署

伺服器部署,跟你的專案架構有關。比如我的部落格專案在服務端有2個後端服務,一個資料庫服務,nginx用於請求轉發:

1460000012440052

5. 遇到的問題及解決辦法

載入不到元件的JS檔案

解決辦法:

去掉webpack配置中的output.chunkFilename: getFileName(‘js/main[name]-$hash.js’)

所以對webpack.server.js不要對配置CommonsChunkPlugin,也不要設定output.chunkFilename

程式碼高亮codeMirror使用到navigator物件,只能在瀏覽器環境執行

把執行邏輯放到mounted回撥中。實現不行,就封裝一個非同步元件,把元件的初始化放到mounted中:

串資料

dispatch的action沒有返回promise,保證返回promise即可

路由跳轉

路由跳轉使用router方法或標籤,這兩種方式能自適應瀏覽器端和服務端,不要使用a標籤

小結

本文主要記錄了我的部落格u3xyz.comSSR過程:

  • 構建webpack改造
  • 程式碼改造
  • server端SSR實現
  • 上線部署

最後希望文章能對大家有些許幫助!

相關文章