記一次 Vue 項目的重構

上週沒有更新原創技術文章,緣由是忙着重構一個新接手的項目,此項目由於項目技術負責人離職,雖然投入人力持續增多,前端達到4人,後端3人,但由於新參與的童鞋對代碼結構和業務的理解,致使項目開發了一個多月,還有一堆問題,達不到上線要求。接手項目以後,一開始對項目業務場景和代碼進行簡單的了梳理,跟了一天項目,觀察提測後FE+RD的狀態,本身也動手改了一天代碼,無論是FE+RD包括本身都以爲實在是太難受了,小坑大坑不斷,因而決定重構。重構不是我的衝動,而是的的確確存在各類大大小小的問題:css

  1. 接口太碎:項目自己按照Vue組件化開發,可是頁面每一個組件獨自採用vuex+ajax請求管理本身的數據,好比:首頁由輪播圖、各類列表和用戶信息展示組成,致使首頁從上到下7~8個模塊,每一個模塊都各自發本身的請求,訪問首頁須要同時發出8個ajax請求前端

  2. 由於「1」提到的,單個組件數據都是使用Vuex進行管理,致使Vuex的store太亂:並且FE按照組件去開發,各自跟後端RD兌接口、聯調,可是沒有人來統籌安排,致使大量重複工做;除此以外,action和mutation中的業務邏輯代碼太多,而不一樣頁面須要不一樣的數據格式,則致使:vue

    1. 或者在mutation當中對數據進行從新整理node

    2. 或者新開個接口,這樣就形成接口愈來愈多,mutation部分代碼愈來愈重。web

  3. 一開始設計或者溝通有誤。好比:用戶信息相關的接口,須要傳入用戶id(uid),而不是經過登陸cookie從passport獲取;第三方接口須要用戶信息,居然請求的時候將cookie發給對方(幸虧cookie是http only的,沒有調通被我及時發現)ajax

  4. 重複代碼太多,抽象能力太差。一份代碼在多個地方複製,致使代碼改來改去最後都不知道哪裏改了哪裏沒改vuex

  5. 命名太亂,包括url、方法名之類,還有錯別字,getAdcontent(用戶地址信息),getmaildetail(用戶地址信息)編程

  6. 研發人員缺少全局意識,只管本身的代碼,而不關心整個流程。因爲先後投入人較多,沒人對整個項目有把控,只能面向本身的需求編程。好比:積分獲取頁面,獲取成功以後,聯調成功,可是實際在積分獲取列表頁面卻沒有相關的記錄信息;在好比:任何用戶均可以領走別人的獎品,緣由後端沒作獎品是不是當前登陸用戶獲取的校驗後端

  7. 問題定位能力不夠,碰見問題一調就是半天,找不到根本問題api

介紹下項目背景:

此項目是一個用戶積分任務和消費項目,一些頁面須要用戶登陸,頁面主要包括:首頁、任務+列表、商品+列表、我的信息和記錄以及其餘類(說明和規則等)
項目用Vue+yog2編寫,ajax請求部分使用vue resource

架構改造

整個項目仍是用Vue+yog2來寫,針對進入頁面分爲兩種狀況:

  1. 第一次經過網站URL進入某個頁面,我稱爲:「首次後端渲染

  2. 非首次已經進入頁面URL後,用戶點擊連接在項目內跳頁,我稱之爲:「非首次跳轉

整個流程整理以下:兩個流程從「兩個小人」開始看起

後端node Server代碼部分

代碼流程以下:

 
 
 
 
router → middleware → page/api action → model → ral請求數據複製代碼

其中在action部分,專門寫了個 baseAction函數,封裝了重複的代碼,使用時傳入用於獲取數據的model方法和處理數據的方法便可。

render部分,針對頁面第一次請求須要將頁面數據放在HTML片斷中chunk輸出,而不是經過ajax請求(爲何不用vue ssr,能夠看下歷史公衆號文章《Vue SSR 從入門到Case Study》,以後單頁內跳轉是ajax請求)。詳細代碼以下:

client.tpl 部分代碼:

baseAction 部分實現chunked

Client Vue部分代碼

client主要流程是:

 
 
 
 
vue router → created時期 判斷是否有頁面數據 →複製代碼提交mutation(有數據),dispatch action(異步拉取數據)→ state觸發修改,頁面dom生成複製代碼

這部分流程圖主要展示是Vuex和Vue resource部分的代碼,經過Vuex的dispatch action,觸發Vue resource的異步請求,等返回數據則commit mutation。

後端渲染+SPA單頁應用

通過改造後整個流程變成:

  1. 「首次後端渲染」:此時須要後端渲染主要HTML+頁面數據,利用chunked,先將不依賴後端數據部分返給瀏覽器,頁面數據和後面的HTML拿到數據後再返給瀏覽器。 client.tpl被「一分爲二」:HTML[0] + HTML[1]

    1. 將頁面通用的css和js lib庫,放在HTML[0]中,首先返回,瀏覽器先解析下載

    2. 業務代碼初始化代碼放在HTML[1], 等到獲取到後臺API數據一塊兒返回

  2. 「非首次跳轉」:這是一個單頁應用的流程,用戶點擊連接,實際走的是vue的router,而後出發vue頁面渲染,URL是經過history pushState mode更改實際URL,這時候若是強刷或者複製url在瀏覽器打開,又走「首次後端渲染」

    1. vue頁面渲染須要的數據是經過vue-resource發起ajax請求,拿到數據以後commit mutation改變state

Vuex梳理

以前代碼每一個組件都單獨ajax請求本身的數據,致使Vuex的module特別多特別亂,並且後端api接口太多太碎,很差維護。最後開發的童鞋本身都在羣裏抱怨,找個action或者mutation都不知道在哪一個文件內,須要搜代碼。。

首先作約定,明確何時使用Vuex:

頁面view相關的數據才使用Vuex來管理,頁面功能性ajax(例如簽到、兌換)不要使用vuex;「首次後端渲染」和「非首次跳轉」的view數據都經過commit mutation來修改state,最終映射到DOM表現上;功能性ajax則在組件內本身發請求實現,保持組件內聚;

P.S:這就是「貧血組件」和「充血組件」的區別,自己組件內的狀態和邏輯都放在全局store管理,會增長store複雜度,下降效率(代碼性能和開發效率)

而後,收斂vuex module

收斂是根據業務頁面作的,前文提到:

頁面主要包括:首頁、任務+列表、商品+列表、我的信息和記錄以及其餘類(說明和規則等)

其中須要數據的有:首頁、任務(詳情、列表)、商品(詳情、列表)和我的中心四個。

改造前module:

改造後module針對業務梳理的四個大頁面內容,保留了四個:

減小mutation數據處理邏輯

複用後端接口數據格式,減小mutation數據處理邏輯

改造前不少action存在下面的代碼(注意箭頭部分):

其中這個循環主要作兩件事情:修改 type、修改 img_urlurl,實際根本沒有必要:

  • 修改 type:實際這已是頁面view層的邏輯了,在vue的模板或者computed中作更合適

  • 修改 img_urlurl:這裏實際是產品的封面圖,改爲 url反而更不合適了,並且致使了數據不一致

代碼能夠直接用 item便可!即不須要作額外的循環處理,保證數據一致性,避免前端的二次設計

API顯性聲明

以前全部的api都是走了一個 proxy,經過node轉發一下,直接到了後臺API接口,代碼以下:

看似很方便甚至有點暗爽的實現,實則帶來了下面的問題:

  1. 接口非顯性聲明,下降可控性,形成無法枚舉有多少接口,各個接口須要什麼參數,增長維護成本

  2. 安全性!後臺這個服務是徹底暴漏給了前端,若是存在敏感的接口,前端js就能夠直接透傳利用

改造後的代碼放在model層,供「首次後端渲染」和「非首次單頁」ajax請求使用:


優化

除了作代碼重構改造外,還在間隙中作了一些優化,這裏記錄一下:

後端渲染使用chunked

詳見本文「後端node server部分代碼」和「後端渲染+SPA」

數據複用

不少頁面設計會在首頁和列表頁面存在有產品的title、圖片和簡單的一些meta,例以下圖:

點擊連接進去詳情頁面能夠直接利用,這部分數據咱們作了複用。

實現方法是:頁面點擊的時候,將該條數據內容commit給下一個頁面的mutation。

緩存

緩存在node和前端Ajax API多有,後端node主要緩存的是首頁,由於首頁須要請求4個接口(接口梳理後),其中三個接口是跟用戶登陸態無關的,這三個接口能夠用lru-cache緩存起來。

前端的ajax api緩存是在 get請求增長的,能夠根據實際狀況用,根據url做爲key,使用sessionStorage存儲(同時cache類本身實現了緩存時間)


技巧

除了優化外,我在介紹下兩個技巧:單頁切換view的loading和統一的錯誤處理。

在單頁跳轉內,下一個view須要API請求獲取數據,而後才能渲染,這時候須要加載個loading顯示(或者作個切換動效)。

原理是:

  1. 利用eventBus,在router中添加兩個事件 closeLoadingvue.action.error,分別用於「關閉loading」和「展示頁面數據錯誤的錯誤頁」

  2. loading展示在router的 beforeEach的鉤子內實現,loading的事件在vuex的action獲取數據成功以後發送

  3. 錯誤的觸發有vuex 的 action / mutation 來發送事件

eventBus也不用本身寫,能夠直接用Vue實例的 $on$emit$once等就夠了,代碼以下:

 
 
 
 
import Vue from 'vue'複製代碼export default new Vue()複製代碼

總結

重構主要作的事情是:

  1. 統一接口請求,從新梳理API;

  2. 收斂Vuex store設計(包括mutation/action的聚合,state簡化);明確Vuex的使用邊界

  3. 明確組件職責邊界,劃分「充血組件」與「貧血組件」

  4. 抽象封裝重複的代碼邏輯

  5. 作了一些簡單優化

說下成果:項目已經delay好久,從4月初到5月初已經一個月了還沒上線,接手項目是五一前,整個重構共2我的力用了三天完成95%的工做,目前已經提測,

下面是重構項目的團隊內部問題總結:

  1. 項目開發中必定要有大局意識,雖然如今項目可能是分組件來的開發方式,可是開發前要跟你們交代清楚約定、規範,什麼該作什麼不應作;

  2. 技術負責人多 check 代碼,防止錯誤的道路上越行越遠;

  3. 要有全局意識,關注整個流程,不要只看到本身的「一畝三分地」,好比:在某個商品頁面,購買/兌換成功了,不要認爲沒有問題了,可能記錄頁面尚未展示(後臺接口沒有入庫);

  4. Don’t repeat yourself!看見重複代碼就渾身難受,「抽象」能力是工程師的基本能力。

  5. 加強debug能力,發現問題直覺就能判斷出來哪一個環境,而後針對性debug


@三水清
未經容許,請勿轉載。
掘金更新比公衆號晚一週左右。
感受有用,歡迎關注個人公衆號,最新文章第一時間看到!
相關文章
相關標籤/搜索