本文首發於 vivo互聯網技術 微信公衆號
連接: https://mp.weixin.qq.com/s/vD9yvYNaxTQBLABik6aqNg
做者:官網商城前端團隊
一年前 vivo 商城仍是以 Java 爲技術核心,先後臺一塊兒,Java 既要負責服務、數據庫,也要負責頁面的渲染。在早期這種開發模式也可以很好的運行。然而隨着業務迭代的加快,前端技術的發展,這種開發模式的弊端愈來愈明顯。主要突出的有如下兩個方面:javascript
到2018年12月,整個商城前端系統隨着不一樣需求疊加積累的緣由,形成了不一樣頁面使用不一樣的技術,比較典型的有jQuery,Vue,FreeMarker,artTemplate,這些不一樣的技術棧從開發來看,相同的內容,在不一樣的頁面可能使用不一樣的技術棧,致使須要開發不少遍,對開發、測試來講工做量都是成倍的增加。css
自2017年微信上線小程序功能後,各類小程序如雨後春筍般出現,vivo 商城一開始也推出了本身的微信小程序,然而因爲業務發展,須要適配的端愈來愈多,原先使用原生開發的小程序方式,沒法作到一套代碼編到多個平臺。前端
爲了提高開發效率,知足高速發展的業務需求,在過去的一年裏,咱們經過對商城內外部系統的全面分析,按照分層的邏輯整理出前端架構的升級指導說明。vue
在《前端架構-從入門到微前端》一書中提到,前端架構自上而下能夠設計爲四個層次,分別爲系統級、應用級、模塊級、代碼級,咱們經過這四個層次來分析vivo商城前端架構升級過程當中的種種思考和實踐,最終造成了一套以Vue + Node.js爲核心的全端架構方案。java
技術演進過程:git
分層架構實施圖:web
即應用在整個系統內的關係,好比如何和後臺通信,如何與其餘應用集成。針對這一級別,咱們進行了先後端分離、多端統1、BFF、SSR等方面的探索和實踐。vuex
架構升級,第一步面臨的問題即是先後端分離,vivo 商城仍然處於業務高速發展時期,不能由於技術重構而停下業務版本的迭代, 所以業務版本迭代必需要和先後端分離同時進行,那怎麼才能作到雙線並行,平滑升級?數據庫
這裏舉個小例子:當咱們分離完成訂單模塊後,就會經過 Nginx 將關於訂單模塊的全部請求轉發到新的靜態資源服務上,以下圖:小程序
經過先後端分離,咱們完全解放前端,讓前端開發效率提高了至少2個檔次。
更多技術細節好比:新老頁面如何同步信息,如何容災容錯等等,請關注咱們的系列第二篇《vivo商城前端架構升級(二):先後端分離篇》
從 PC 瀏覽器,到移動端瀏覽器、到 App 內嵌,再到各個小程序,再到服務端、客戶端。繁榮的生態,猶如百家爭鳴,百花齊放。然而,繁榮的背後,對前端工程師的挑戰,則與日俱增。
咱們承接的端愈來愈多,新的端不斷的出現,如小程序、快應用等。前端工程師陷入了以下套娃陷阱:
- 現有代碼、新代碼要適配新的端開發場景
- 已經適配新的端開發場景的代碼成爲了現有代碼
- 現有代碼、新代碼要適配新的端開發場景
- 循環...
咱們但願解決這種問題,但願作到一套技術架構方案【代碼】,能夠覆蓋如今的端和將來的端。
通俗點說,咱們但願作到以下圖所示的能力:
在這種前端開發背景下,多端統一出現了。它是前端的一個將來趨勢,它也是解決上面套娃陷阱的一劑良藥。
更多細節內容,請關注咱們的系列第三篇《vivo商城前端架構升級(三):多端實踐篇》
隨着端的增多,新的接口數量呈現爆發式增加,老的接口爲了適配各端,也會增長了各類不一樣的字段,致使先後端適配多端的工做量愈來愈大。可是抽象來看,大部分端的變更都是UI層級的變更,不多有底層服務的改變,因此帶來了一個問題接口到底是面向UI,仍是面向通用服務?
爲了解決這個問題,Sam Newman 發表了一篇文章,講述了這種體驗者專用 API 的方式,並將其稱爲BFF(Backends for Frontends)模式。
在BFF理念中,最重要的一點是:服務自治,誰使用誰開發。服務自治減小了溝通成本,帶來了靈活和高效。
商城前端積極適應前端技術的發展,爲了提供一流的用戶體驗,積極推進BFF層在商城業務中的實現。
Apache Dubbo 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。
咱們使用了社區提供的 Dubbo2.js 進行 Dubbo 服務的調用,而且作了一些封裝來優化發開體驗。
GraphQL 是一個開源的 API 數據查詢和操做語言及實現爲了實現上述操做的相應運行環境。相較於REST以及其餘 web service架構提供了一種高效、強大和靈活的開發 web APIs的方式。
(1)請求你所要的數據 很少很多
(2)獲取多個資源 只用一個請求
(3)強大的API調試工具
自從先後端分離後,前端採用了SPA技術,走的都是CSR(客戶端渲染)的模式。使用CSR的優點在於節省後端資源、局部刷新等,但隨着應用的日益複雜,首屏渲染時間不斷變長, 而且存在嚴重的 SEO 問題。因此爲了解決SPA應用遇到的這些問題, 咱們必須考慮 SSR。
SSR 即服務端渲染,是指由服務器端完成頁面的HTML 結構拼接,而且直接將拼接好的HTML發送到瀏覽器,而後爲其綁定狀態與事件,成爲徹底可交互頁面的處理技術。
主要優點在於:
爲了不重複造輪子,咱們使用了社區很是優秀的SSR框架nuxt,經過一系列的優化,好比:頁面緩存、組件緩存、API緩存、最小化渲染等方式,最終讓咱們頁面在500ms內就能所有展現,這是用戶體驗上的極大提高。
即應用外部的總體架構,如多個應用之間如何共享組件、如何通訊、如何開發通用腳手架等。在應用級別的架構上面,咱們主要沉澱了適用於商城的UI庫,爲其餘商城衍生項目提供基礎組件支持。
移動端的設計變幻無窮,市場上很是流行的移動端的組件庫好比antd-mobile , vant,他們對於開發通用型的 App,很是高效且美觀,然而大部分自主研發的 App都有本身的一套設計風格和理論。若是使用流行的組件庫,就會出現頻繁須要修改源碼,以適應UI風格的變化。這樣的工做量日積月累,就會變得愈來愈大。因此咱們仍是建議若是是作本身特點的App,仍是要自建UI庫。若是感受自建UI庫難度較大,能夠先fork一份流行的組件庫,學習其中的各類實現,慢慢造成本身的UI庫。
商城也實現了本身的UI庫,目前已經在商城、秒殺、vivo 內購、v客聯盟等應用中普遍使用,極大的提升了開發效率。以下圖:
應用內部的模塊架構,如代碼的模塊化、數據和狀態的管理等,在項目中比較典型的是咱們設計了針對 Vue 的極致模塊化方案,頂層 page 設計,數據自治等方面的工做。
咱們的方案擯棄了官方推薦的按文件類型組織模塊,而採用按照功能組織模塊,這種"可插拔式"組件設計,讓代碼按照功能聚合。
一個文件包裏面包含該功能的全部實現,包括圖片、樣式、腳本、數據流、組件等等,這樣另外一個項目想要使用,直接遷移便可,極大地減小了遷移的成本,而且還有一個優點是,若是這個功能之後下架,直接刪除便可,沒必要各個文件夾下找文件,極大地提高了代碼的簡潔性和可維護性。
➜ confirm git:(dev_abtest_gray) tree . ├── api.js // 接口資源 ├── components // 內部組件 │ ├── component1 │ │ ├── images │ │ ├── index.scss │ │ └── index.vue │ ├── component2 ├── images // 圖片資源 ├── index.scss // 樣式資源 ├── index.vue // 邏輯實現 ├── module.js // 數據流 └── trackData.js // 埋點
全部的頁面都會有不少通用的功能,好比加載前的骨架圖、出錯後的處理邏輯、數據採集邏輯、上拉刷新、下滑分頁加載,全局 iOS 適配等等,這些功能在邏輯上是須要抽象的,避免各個頁面屢次實現,致使浪費開發資源和下降程序的可維護性。
針對此咱們實現了一個頂級 page 組件,全部的頁面都繼承於這個 page 。作到通用性的功能全局管理。
頂級 page 的部分 API 使用以下:
<template> <v-page // 頁面是否完成 :pageInit="true" // 頁面是否出錯 :pageError="false" // 頁面監控開啓,包括pv,uv,渲染時間 :pageMonitor="true" // 上拉刷新 @pullDownRefresh="pullDownRefresh" // 下拉監聽 @reachBottom="reachBottom" // 滾動監聽 @pageScroll="pageScroll" > <template slot="header"> <!-- 自定義頭部,若是沒有則使用默認頂部導航菜單 --> <Header /> </template> <template slot="skeleton"> <!-- 本身實現的骨架圖,若是沒有則使用默認骨架圖--> <Skeleton /> </template> <template slot="footer"> <!-- 本身實現的底部,吸底顯示,若是沒有則不顯示--> <Footer /> </template> </v-page> </template>
本着誰使用,誰負責的原則,對於頁面中的數據流也是同樣的,咱們開發了針對page的全局mixin,負責自動註冊和卸載頁面數據,並將各個頁面之間的數據進行隔離。
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex' export default (name, module) => ({ computed: { ...mapState(name, Object.keys(module.state)), ...mapGetters(name, Object.keys(module.getters)) }, created () { // todo 要加判斷是否已經註冊,動態註冊模塊 if (!(name in this.$store._modules.root._children)) { this.$store.registerModule(name, module) } }, methods: { ...mapActions(name, Object.keys(module.actions)), ...mapMutations(name, Object.keys(module.mutations)) } })
當咱們開始編寫代碼的時候,就要考慮代碼的規範和質量。規範的目的是爲了提高維護性,而質量則是開發的門面,一個好的項目離不開這這兩個內容的約束。
一個好的規範應該作到簡單、好記、易於執行。爲了實現這個目標,咱們制定了一系列的規範,最主要的是開發規範、提交規範。
每一個項目組的規範可能都不同,須要根據本身的項目特點,能夠參考優秀的項目實踐,整理出本身的項目規範,小組內部討論優化,達成一致意見,最後發佈執行。每一位新進項目組的成員,首先要作的就是學習這些規範,用規範引導開發。
(1)開發規範
包含但不侷限於如下內容:命名規範、HTML 規範、css規範、js規範。
(2)提交規範:
爲了規範提交代碼,從而方便開發者追蹤項目的開發信息和功能特性,咱們封裝了@vivo/commit,對咱們的提交進行強制校驗。好比:
每一條commit由四個部分組成,以下圖:
style: 樣式修改fix: bug修復
feat: 功能開發
refactor: 代碼重構
test: 測試類修改
doc: 文檔更新
conf: 配置修改
merge: 代碼合併
每一條commit,應明確指出其影響範圍是哪一個模塊,若是是通用模塊,註釋上(全局)字樣,方便code reviewer對方案進行評估
每一條commit,必需要有單號,每一個公司都有本身的缺陷跟蹤系統,單號的目的是爲了讓每一條提交有據可循,方便後續對問題的回溯。
問題描述應該簡潔明瞭,讓其餘人一看就知道這條commit修改了什麼,禁用一些通用描述,好比:'修改了一個bug','添加了一個功能'
關於質量咱們從兩個方面進行提高,代碼檢視 和 代碼覆蓋率。
(1)代碼檢視:
爲了提升代碼檢視的效率,調研了市場上面衆多的代碼檢視工具,好用都須要收費,而且功能比較複雜,好比:upsource。因而開發了一個基礎vscode的code review插件,支持GitLab,實時消息通知。
添加評論
(2)代碼覆蓋率:
商城的業務迭代速度很是快,使得開發單元測試開發的成本很是大,然而咱們有時又想看看測試場景的覆蓋狀況,爲了實現這些目標,咱們研發了集成測試代碼覆蓋率平臺。經過這個平臺能夠清晰的看到每一行代碼被測試執行的狀況。保證了開發的質量,並能給測試提供精確的指導建議。
本篇文章介紹了 vivo 商城架構升級的背景,並從系統級、應用級、模塊級、代碼級四個層次,總結了 vivo 商城前端架構升級過程當中的種種實踐和探索,但願能給有相似需求的團隊帶來幫助。
咱們在前端技術方面的探索並未結束,做爲前端架構升級的第一篇,後面會圍繞架構升級帶來一系列的文章,爲你們更詳細的講解其中的難點和經驗,敬請期待。
更多內容敬請關注vivo 互聯網技術微信公衆號
注:轉載文章請先與微信號:Labs2020聯繫