用Vue開發小程式的框架
在尤大微博鋪墊著“將會引入一些關於 TypeScript 的改進”一週之後,代號為 Level E 的 Vue.js 2.5 帶著日漫風來到了我們眼前。從 Release Notes 可以看到,Vue.js 2.5 有著更好的 TypeScript 整合,更好的錯誤處理,更好地支援單檔案元件中的函式式元件以及與環境無關的服務端渲染。
具體如下:
更好的 TypeScript 整合
得益於 TypeScript 團隊的幫助,2.5 提供了大大改進的型別宣告:
-
使用預設的 Vue API 時,對於 this 可以使用適當的型別推斷。 它也可以在單檔案元件中工作!
-
基於元件的 props 選項,對於 this 中的 props 輸入推斷。
-
最重要的是,
這些改進也使得純 JavaScript 使用者受益匪淺!
如果你使用 VSCode 與超級棒的的 Vetur 擴充套件,你將獲得大大改進的自動完成建議,甚至在Vue元件中使用純 JavaScript 時也能獲得輸入提示! 這是因為vue-language-server是負責分析 Vue 元件的內部包,可以利用 TypeScript 編譯器來提取有關你的程式碼的更多資訊。 此外,任何支援語言伺服器協議的編輯器都可以利用 vue-language-server來提供類似的功能。
注意:TypeScript 使用者還應將以下包更新為最新版本從而相容型別宣告:vue-router,vuex,vuex-router-sync 和 vue-class-component。
更好地錯誤處理
在 2.4 及更早版本中,我們通常使用全域性 config.errorHandleroption 來處理應用程式中的意外錯誤。 我們還有 renderError 元件選項來處理渲染函式中的錯誤。 但是,我們缺少處理應用程式特定部分內的泛型錯誤的機制。
在2.5中,我們引入了新的 errorCaptured 鉤子。 具有此鉤子的元件捕獲其子元件樹(不包括其自身)中的所有錯誤(不包括在非同步回撥中呼叫的那些)。 如果你熟悉 React,這與 React 16 中引入的錯誤邊界的概念相似。鉤子接收與全域性 errorHandler 相同的引數,你可以利用這個 鉤子(https://
更好地支援 SFC 中的函式式元件
使用 vue-loader> = 13.3.0 和 Vue 2.5,在 * .vue 檔案中定義為單個檔案元件的函式式元件現在可以得到正確的模板編譯,Scoped CSS和熱重新載入支援。 這使得將葉子元件轉換為函式式的更為容易,從而進行效能優化。
與環境無關的服務端渲染
vue-server-renderer 的預設構建假定一個 Node.js 環境,這使得它在有的 JavaScript 執行時(如 php-v8js 或Nashorn)中不可用。 在 2.5 中,我們已經發布了一個與環境無關的 vue-server-renderer 版本,可以在瀏覽器或純 JavaScript 引擎中使用。 這可以開啟有趣的策略,例如直接在 PHP 程序中使用 Vue 服務端渲染。
同樣,建議你檢視完整的釋出說明從而瞭解其他 API 的改進,包括 v-on,v-model,scoped slot,provide/inject 等。
Vue.js 這款漸進式的 JavaScript 框架自 2013 年釋出至今,其簡潔的語法設計、輕量快速的特點深受技術社群喜愛,在國內外都獲得了非常廣泛的應用及拓展,比如餓了麼的開源元件庫 Element UI 即是 Vue 開發,而阿里巴巴的 Weex 與 Vue 也多有合作。
今天,我們來介紹一款由美團點評研發,使用 Vue.js 來開發微信小程式的前端框架 —— mpVue。使用此框架,開發者將得到完整的 Vue.js 開發體驗,同時為 H5 和小程式提供了程式碼複用的能力。如果想將 H5 專案改造為小程式,或開發小程式後希望將其轉換為 H5,mpVue將是十分契合的方案。
為了提高開發效率,增強開發體驗,我們造了個用 Vue 開發小程式的輪子
小程式開發特點
微信小程式推薦簡潔的開發方式,通過多頁面聚合完成輕量的產品功能。小程式以離線包方式下載到本地,通過微信客戶端載入和啟動,開發規範簡潔,技術封裝徹底,自成開發體系,有 Native 和 H5 的影子,但又絕不雷同。
小程式本身定位為一個簡單的邏輯檢視層框架,官方並不推薦用來開發複雜應用,但業務需求卻難以做到精簡。複雜的應用對開發方式有較高的要求,如元件和模組化、自動構建和整合、程式碼複用和開發效率等,但小程式開發規範較大地限制了這部分能力。為了解決上述問題,提供更好的開發體驗,我們創造了 mpVue,通過使用 Vue.js 開發微信小程式。
mpVue 是什麼
mpVue 是一套定位於開發小程式的前端開發框架,其核心目標是提高開發效率,增強開發體驗。使用該框架,開發者無須瞭解小程式開發規範,只需要熟悉 Vue.js 基本語法即可上手。框架提供了完全的 Vue.js 開發體驗,開發者編寫 Vue.js 程式碼,mpVue 將其解析轉換為小程式並確保其正確執行。此外,框架還通過 CLI 工具向開發者提供 Quick Start 示例程式碼,開發者只需執行一條簡單命令,即可獲得可執行的專案。
為什麼做 mpVue
在小程式內測之初,我們計劃快速迭代出一款對標 H5 的產品實現,其核心訴求在於快速實現、程式碼複用、低成本和高效率等。隨後我們經歷了多個小程式建設,結合業務場景、技術選型和小程式開發方式,整理彙總出了開發階段面臨的主要問題:
- 元件化機制不夠完善;
- 程式碼多端複用能力欠缺;
- 小程式框架和團隊技術棧無法有機結合;
- 小程式學習成本不夠低。
具體體現為:
- 元件機制:小程式邏輯和檢視層程式碼彼此分離,公共元件提取後無法聚合為單檔案入口,元件需分別在檢視層和邏輯層引入,維護性差;元件無名稱空間機制,事件回撥必須設定為全域性函式,元件設計有命名衝突的風險,資料封裝不強。開發者需要友好的程式碼組織方式,通過 ES 模組一次性匯入;元件資料有良好的封裝。成熟的元件機制,對工程化開發至關重要。
- 多端複用:常見的業務場景有兩類,通過已有 H5 產品改造為小程式應用或反之。從效率角度出發,開發者希望通過複用程式碼完成開發,但小程式開發框架卻無法做到。我們曾嘗試通過靜態程式碼分析將 H5 程式碼轉換為小程式,但只做了檢視層轉換,無法帶來更多收益。多端程式碼複用需要更成熟的解決方案。
另一方面,小程式開發方式與 H5 近似,因此我們考慮和 H5 做程式碼複用。同時,沿襲團隊技術棧選型,我們將 Vue.js 確定為小程式開發規範。使用 Vue.js 開發小程式,將直接帶來如下開發效率的提升:
- H5 程式碼可以通過最小修改複用到小程式;
- 使用 Vue.js 元件機制開發小程式,可實現小程式和 H5 元件複用;
- 技術棧統一後小程式學習成本降低,開發者從 H5 轉換到小程式不需要更多學習;
- 程式碼維護成本降低,Vue.js 程式碼可以讓所有前端直接參與開發維護。
為什麼是 Vue.js?這取決於團隊技術棧選型,引入新的選型對統一技術棧和提高開發效率相悖,有違開發工具服務業務的初衷。
mpVue 的演進
mpVue 的形成,來源於業務場景和需求,最終方案的確定,經歷了三個階段。
- 第一階段:我們實現了一個檢視層程式碼轉換工具,旨在提高程式碼首次開發效率。通過將 H5 檢視層程式碼轉換為小程式程式碼,包括 HTML 標籤對映、Vue.js 模板和樣式轉換,在此目的碼上進行二次開發。我們做到了有限的程式碼複用,但元件化開發和小程式學習成本並未得到有效改善。
- 第二階段:我們著眼於完善程式碼元件化機制。參照 Vue.js 元件規範設計了程式碼組織形式,通過程式碼轉換工具將程式碼解析為小程式。轉換工具主要解決元件間資料同步、生命週期關聯和名稱空間問題。最終我們實現了一個 Vue.js 語法子集,但想要實現更多特性或跟隨 Vue.js 版本迭代,工作量變得難以估計,有永無止境之感。
- 第三階段:我們的目標是實現對 Vue.js 語法全集的支援,達到使用 Vue.js 開發小程式的目的。並通過引入 Vue.js RunTime 實現了對 Vue.js 語法的支援,從而避免了人肉語法適配。至此,我們完成了使用 Vue.js 開發小程式的目的。較好地實現了技術棧統一、元件化開發、多端程式碼複用、降低學習成本和提高開發效率的目標。
mpVue 設計思路
Vue.js 和小程式都是典型的邏輯檢視層框架,邏輯層和檢視層之間的工作方式為:資料變更驅動檢視更新;檢視互動觸發事件,事件響應函式修改資料再次觸發檢視更新,如圖 1 所示。
圖 1 小程式實現原理
鑑於 Vue.js 和小程式一致的工作原理,我們思考將小程式的功能託管給 Vue.js,在正確的時機將資料變更同步到小程式,從而達到開發小程式的目的。這樣,我們可以將精力聚焦在 Vue.js 上,參照 Vue.js 編寫與之對應的小程式程式碼,小程式負責檢視層展示,所有業務和邏輯收斂到 Vue.js 中,Vue.js 資料變更後同步到小程式,如圖 2 所示。如此一來,我們就獲得了以 Vue.js 的方式開發小程式的能力。為此,我們設計的方案如下:
圖 2 mpVue 實現原理
Vue 程式碼:
- 將小程式頁面編寫為 Vue.js 實現;
- 以 Vue.js 開發規範實現父子元件關聯。
小程式程式碼:
- 以小程式開發規範編寫檢視層模板;
- 配置生命週期函式,關聯資料更新呼叫;
- 將 Vue.js 資料對映為小程式資料模型。
並在此基礎上,附加如下機制:
- Vue 例項與小程式 Page 例項建立關聯;
- 小程式和 Vue 生命週期建立對映關係,能在小程式生命週期中觸發 Vue 生命週期;
- 小程式事件建立代理機制,在事件代理函式中觸發與之對應的 Vue 元件事件響應。
這套機制總結起來非常簡單,但實現卻相當複雜。在揭祕具體實現之前,讀者可能會有這樣一些疑問:
- 要同時維護 Vue.js 和小程式,是否需要寫兩個版本的程式碼實現?
- 小程式負責檢視層展現,Vue.js 的檢視層是否還需要,如果不需要應該如何處理?
- 生命週期如何打通,資料同步更新如何實現?
上述問題包含了 mpVue 框架的核心內容,下文將仔細為你道來。首先,mpVue 為提高效率而生,本身提供了自動生成小程式程式碼的能力,小程式程式碼根據 Vue.js 程式碼構建得到,並不需要同時開發兩套程式碼。
Vue.js 檢視層渲染由 Render 方法完成,同時在記憶體中維護著一份虛擬 DOM,mpVue 無需使用 Vue.js 完成檢視層渲染,因此我們改造了 Render 方法,禁止檢視層渲染。熟悉原始碼的讀者都知道 Vue RunTime 有多個平臺的實現,除了我們常見的 Web 平臺,還有 Weex。從現在開始,我們增加了新的平臺 mpVue。
再看第三個問題,生命週期和資料同步是 mpVue 框架的靈魂,Vue.js 和小程式的資料彼此隔離,各自有不同的更新機制。mpVue 從生命週期和事件回撥函式切入,在 Vue.js 觸發資料更新時實現資料同步。小程式通過檢視層呈現給使用者、通過事件響應使用者互動,Vue.js 在後臺維護著資料變更和邏輯。可以看到,資料更新發端於小程式,處理自 Vue.js,Vue.js 資料變更後再同步到小程式。為實現資料同步,mpVue 修改了 Vue.js RunTime 實現,在 Vue.js 的生命週期中增加了更新小程式資料的邏輯。
而使用者互動觸發的資料更新則是通過事件代理機制完成。在 Vue.js 程式碼中,事件響應函式對應到元件的 method 方法,Vue.js 自動維護了上下文環境。然而在小程式中並沒有類似的機制,又因為 Vue.js 執行環境中維護著一份實時的虛擬 DOM,這與小程式的檢視層完全對應。我們思考,在小程式元件節點上觸發事件後,只要找到虛擬 DOM 上對應的節點,觸發對應的事件不就完成了麼。Vue.js 事件響應如果觸發了資料更新,其生命週期函式更新將自動觸發,在此函式上同步更新小程式資料,資料同步就實現了。
mpVue 如何使用
mpVue 框架本身由多個 npm 模組構成,入口模組已經處理好依賴關係,開發者只需要執行如下程式碼即可完成本地專案建立。
安裝 vue-cli
$ npm install --global vue-cli
根據模板專案建立本地專案,目前為內網地址,暫穩開放
$ vue init ‘bitbucket:xxx.meituan.com:hfe/mpvue-quickstart’ --clone my-project
安裝依賴和啟動自動構建
$ cd my-project
$ npm install
$ npm run dev
執行完上述命令,在當前專案的 dist 子目錄將構建出小程式目的碼,使用小程式開發者工具載入 dist 目錄即可啟動本地除錯和預覽。
示例專案遵循 Vue.js 模板專案規範,通過 Vue.js 命令列工具 vue-cli 建立。程式碼組織形式與 Vue.js 官方例項保持一致,我們為小程式定製了 Vue.js RunTime 和 Webpack 載入器,此部分依賴也已經內建到專案中。
針對小程式開發中常見的兩類程式碼複用場景,mpVue 框架為開發者提供瞭解決思路和技術支援,開發者只需要在此指導下進行專案配置和改造。
將小程式轉換為 H5
直接使用 Vue.js 規範開發小程式,程式碼本身與 H5 並無不同,具體程式碼差異會集中在平臺 API 部分。此外無需明顯改動,改造主要分以下幾個部分:
- 將小程式平臺的 Vue.js 框架替換為標準 Vue.js;
- 將小程式平臺的 Vue-loader 載入器替換為標準 Vue-loader;
- 適配和改造小程式與 H5 的底層 API 差異。
將 H5 轉換為小程式
已經使用 Vue.js 開發完 H5,則需要完成以下事宜:
- 將標準 Vue.js 替換為小程式平臺的 Vue.js 框架;
- 將標準 Vue-loader 載入器替換為小程式平臺的 Vue-loader;
- 適配和改造小程式與 H5 的底層 API 差異。
根據小程式開發平臺提供的能力,我們最大程度地支援了 Vue.js 語法特性,但部分功能現階段暫時尚未實現,具體見表 1。
表 1 mpVue 暫不支援的語法特性
mpVue 框架的目標是將小程式和 H5 的開發方式通過 Vue.js 建立關聯,達到最大程度的程式碼複用。但由於平臺差異的客觀存在(主要集中在實現機制、底層 API 能力差異),我們無法做到程式碼 100%複用,平臺差異部分的改造成本無法避免。對於程式碼複用的場景,開發者需要重點思考如下問題並做好準備:
- 儘量使用平臺無的語法特性,這部分特性無需轉換和適配成本;
- 避免使用不支援的語法特性,譬如 slot、filter 等,降低改造成本;
- 如果使用特定平臺 API,考慮抽象好適配層介面,通過切換底層實現完成平臺轉換。
mpVue 最佳實踐
在表 2 中,我們對微信小程式、mpVue、WePY 這三個開發框架的主要能力和特點做了橫向對比,幫助大家瞭解不同框架的側重點,結合業務場景和開發習慣,確定技術方案。對於如何更好地使用 mpVue 進行小程式開發,我們總結了一些最佳實踐。
表 2 框架主要能力及特性對比
- 使用 vue-cli 命令列工具建立專案,使用 Vue 2.x 的語法規範進行開發;
- 避免使用不框架不支援的語法特性,即有部分 Vue.js 語法在小程式中無法使用,儘量 mpVue 和 Vue.js 共有特性;
- 合理設計資料模型,對資料的更新和操作做到細粒度控制,避免效能問題;
- 合理使用元件化開發小程式,提高程式碼複用。
結語
mpVue 框架已經在業務專案中得到實踐和驗證,目前開發文件也已經就緒,正在做開源前的最後準備,希望能夠為小程式和 Vue.js 生態貢獻一份力量。mpVue 的初衷是希望讓 Vue.js 的開發者以低成本接入小程式開發,其能力和使用體驗還有待進一步的檢驗。我們未來會繼續擴充套件現有功能、解決使用者的問題和需求、優化開發體驗、完善周邊生態建設,以幫助到更多的開發者。
需要說明一下,mpVue 是通過 fork Vue.js 原始碼進行二次開發,新增加了 mp 平臺的 Vue.js 實現,我們保留了跟隨 Vue.js 版本升級的能力,希望未來能夠實現更好的能力增強,最後感謝 Vue.js 框架和微信小程式對業界帶來的便利