龔澄,常用ID: Gcaufy,小程式開源框架 WePY 作者,熱愛技術,熱愛開源。於2015年加入騰訊,負責騰訊手機充值相關業務的開發。2018年加入微信支付,負責微信支付商戶側業務小程式的開發。
引言
本主題雖然在其它地方講了很多次,但還是有非常多新內容。因為很多東西正在做或者想要做。本次分享主要分為以下幾個部分:

WePY 的介紹

WePY 的使用者

上面展示的 WePY 使用者不是全部的資料。因為沒有辦法讓 WePY 使用者主動上報自己在使用 WePY,所以我只列了我知道的在使用 WePY 的公司,資料比較有限。
就我所知道的,最近有一個刷爆朋友圈的小程式 —— 騰訊疫苗,前端採用的 WePY,後端用了騰訊開源的 TARS 專案。微信支付內部也有大量小程式在使用 WePY 框架。
右邊貼的聊天記錄是我在 WePY 交流群收集到的使用者反饋,就反饋的內容來看,有很多感謝的話,說明 WePY 這個框架確實能幫助開發者提高自己的開發效率。嘿嘿,我沒有貼 WePY 的負面反饋,因為我擔心一頁 PPT 不夠貼 ?。
WePY 的資料

WePY 專案在 Github 上現在有13900多個 Star。拿其它前端框架對比,Vue、React 等 Star 數可能達到了 10W+,但是它們都是國際的專案。WePY 這個專案由於微信小程式的原因,算是一個國內專案,能有13000多個 Star 還是相當不錯的。Star 數多不一定代表 WePY 這個框架好,但是能表明小程式這塊流量很大,開發小程式也非常有前景。 開發者們需要 WePY 這樣的框架來提供幫助。這也是為什麼後來出現了 Taro、mpvue 等類似的非常優秀的框架。
issues 目前有1300多個。這意味著我每天起床都有超過10條 to-do list 需要處理。加上每天還有公司的其它事情需要處理,比較頭大。
pull requests 目前有320多條。相比其它開源專案,這個 PR 數量相當不錯,非常感謝為 WePY 作貢獻的開發者們。
使用者數有4000多。這個資料的來源我是統計的我建立的 WePY 交流群,目前這個交流群裡有 4000 多人。
WePY 是什麼

將 Web App 和小程式進行對比。Web App 和小程式在功能上類似, Web App 在開發的時候,可能使用 Vue.js 作為其核心庫,用 Webpack 進行打包。在微信小程式中,大家可以簡單的將 WePY 理解為 Web App 裡的 Vue.js + Webpack 的合體。
WePY 的特點

WePY 在開發中到底幫助開發者做了什麼事情呢?WePY 又有哪些特點呢?
- 腳手架:它提供了一個相當於 vue-cli 的腳手架,一行命令生成簡單的 demo 專案。使用者可以基於這個 demo 進行開發,省去了啟動專案前繁瑣的配置。
- 編譯打包:原生開發小程式缺失了許多能力,比如 LESS、SASS。很多使用者面對這個問題都是做一個簡單的 Gulp 編譯。WePY 自帶了編譯打包能力,想用 LESS、SASS、NPM 等可以直接使用 WePY 的打包工具輸出小程式可以執行的程式碼。
- 核心庫:核心庫類似 Vue、React 等。WePY 核心庫包含一些簡單的 API 封裝幫助處理一些事情。
- 特性與優化:開發上,WePY 提供了一些語法糖,可以簡單方便的實現一些複雜功能。效能上,小程式本身的效能有一些問題,WePY 把效能上的問題抹平了,開發者不用關心效能這部分。
- 複用與擴充套件:複用方面,原生小程式使用 npm 資源需要將相對應的資源下載並放到程式碼目錄中,利用 WePY 可以直接安裝 npm 包並使用。擴充套件方面,在編譯過程中,可以隨意新增和擴充套件編譯手段,比如 LESS、SASS、編譯外掛等。
- 多端:利用 WePY 可以將一份程式碼執行在小程式、H5 等端。
WePY 的規劃

16年8月參加小程式內測,10月份開始著手程式碼轉換相關的工作。在不停的迭代中,我發現還有很多事情可以做。比如可以將相關的工作抽象出來提供給其它開發者。於是在11月我對程式碼進行了重構,將 Gulp 編譯部分拋棄重寫並於 Github 開源1.1版本。
開源之後有很多人關注到這個專案,說明還是有不少人遇到了相應的問題。因此我做了更加具體的優化,在1.1版本上又一次重構,把編譯流程抽象,提出了編譯器和外掛兩個概念,方便使用者進行擴充套件。
17年1月份釋出1.4版本,對整個開發流程和開發者使用框架時的體驗進行了更多優化,包括效能優化等。
1.6 版本開始考慮多端問題:小程式一套程式碼多端複用。
17年11月左右,小程式推出了原生元件。WePY 本身就是為了解決小程式元件的問題,原生元件釋出之後,WePY 的使用場景就沒有以前那麼強了,所以我開始思考, WePY 需要做一個完全重構的版本。
18年2月份啟動了該重構版本,這個版本主要是為了解決小程式原生元件相關的問題,是一個全新的重構版本。但由於各種原因,這個版本還沒有正式公佈。敬請期待!
WePY 的實現原理

接下來我會講一下 WePY 在技術上的實現原理。
WePY 解決的問題

任何一個專案都是發現問題,解決問題的過程,WePY 要解決的問題就是:
- 元件化開發:小程式原生元件出現之前,小程式沒有很好的元件化開發模式。比如我自己實現了一套 dialog,別人想使用的時候可能要把我的程式碼拷貝一份。實現了元件化之後,我只要把這個元件給他就好了。
- npm 資源:Web 發展至今,npm 庫上有非常龐大的資源。但是原生小程式沒有使用 npm 資源的能力,WePY 提供了這個功能。
- 前端工程化:前面提及的打包構建部分
- 效能優化
- 友好的開發體驗:體驗優化
- 跨平臺支援:多端這部分
總的來說,WePY 解決的問題就是開發中遇到的痛點問題。
WePY 的架構

上面是我寫的兩個核心的部分:CLI 以及 Core。Core 通過 CLI 編譯,生成小程式端執行的程式碼。CLI 部分又分為 wepy、wepy-web ,分別負責 wepy 的編譯和 wepy-web 的編譯。其上又分為編譯器和外掛兩部分,編譯器涉及到目前主流的前處理器,類似 Webpack 的 loader 。外掛是在編譯之後要做的事情,類似於 Webpack 的 plugin。Core 部分分為 wepy 核心庫、小程式核心庫和 wepy-web 核心庫。wepy-web 核心庫比小程式多了 wepy components 和 wepy API 。小程式本身的一些內建元件,比如彈窗元件,想要多端執行都需要封裝起來放在 wepy components 。小程式原生 API 需要通過 wepy API 封裝。
web 本身還分很多平臺種類,比如 browser、微信 h5、QQ h5,這些都需要分別適配,所以 wepy-web 之上是一個適配層。
整個 Core 之上,是使用者封裝的一些元件,比如上報、非同步。還有一些功能元件,比如使用者做的彈窗、toast、imageloader 等。
縱觀整個 WePY,我的程式碼會通過 CLI 基於 Core 輸出小程式端執行的程式碼。
WePY 的編譯過程

WePY 本身定義了一個檔案字尾 .wpy 。編譯時將該檔案解析並拆分為 Style、Template、Script。拆分時,會解析並記錄元件關係,包括事件、引用等。每個節點的資訊都會被記錄,在注入時生成到 JS 中,在 JS 中就可以知道元件關係並進行呼叫。生成完之後進入到 plugin,plugin 是使用者自定義的,需要進行圖片壓縮、JS 混淆、wxml 壓縮等處理。依次做完這些處理之後才會得到可以在小程式中執行的程式碼。
以上就是 WePY 的整個編譯過程。
多端的實現

在實現多端方面,面臨著以下問題:
-
開發模式
小程式開發模式自成一派,與現有開發模式都不相同。好在使用 WePY 開發時,WePY 使用的是類 Vue 的開發語法,跟 Vue 開發模式很貼近,所以開發模式問題藉助 WePY 非常好解決。
-
標籤與樣式
小程式與 H5 的標籤不一樣,但是可以直接做一些簡單的轉換處理。比如
<view>
轉換為<div>
。樣式上小程式有一個 rpx 單位,在 750 px 的情況下直接 /2 將 rpx 轉為 px。 -
模版語法
小程式有自己的模版語法,比如
<wx-if>
等,解析時可以做簡單的轉換。 -
模組化
小程式原生可以使用
require
,但是H5不可以。好在有很多工具值得借鑑,比如 webpack,browserify。 -
內建元件及內建 API
WePY 本身使用的是類 Vue 的語法,要轉換為 Vue 執行在 Web 端的話,內建元件直接使用 Vue 的形式編寫,使用時直接引入這個 Vue 元件。內建 API 使用 WePY 提供的 JSSDK 去模擬微信端、H5等提供的 API。
因此,多端實現完全可行。我們的一些專案完全利用 WePY 實現多端。
生態

左邊是在 Github 上看到的一些 UI 庫,大家在使用 WePY 開發的時候可以直接利用這些 UI 庫進行二次開發。右邊是網上收集到的開發資源,包括開發元件、第三方模組等。Github 上 WePY 關鍵字搜尋結果有900多頁。從使用者反饋來看,使用者選擇 WePY 的一個原因也是 WePY 誕生的時間長,生態比較完善。
WePY 的規劃

現有問題

WePY 目前存在的核心問題是
-
靜態元件編譯
WePY 專案做的比較倉促,花了大概一個多月就上線了。最開始只是為了解決元件化的問題。因此它採用了靜態元件編譯這套方案,在編譯元件時,直接將我寫的元件進行靜態替換,將我寫的元件注入到頁面中,做了一些隔離相關的事情。這導致動態 repeat 時會出現比較嚴重的 BUG。這是設計上的缺陷,也是急需解決的問題。
-
語法解析
xml 的解析用了一個存在問題的庫,導致 xml 解析時經常出錯。js 的解析設計之初沒有考慮用語法樹解析,而是使用正則進行解析。因為目前僅涉及解析和語法注入,實現起來都比較簡單,所以沒有考慮用 AST 語法樹進行解析,導致使用者沒有按照規範寫的一些程式碼在解析時會出現錯誤。
-
類 Vue 語法
從使用者的反饋來看,大家更希望用 Vue 的語法而不是類 Vue 語法。這兩個之間還是有一些差異的。
-
資料繫結效能優化
資料繫結時做了一些優化和處理。但這些優化和處理是通過髒資料進行的,幫助使用者減少 setDate 的次數。但是後來再看,這塊還是有可以優化的空間。
-
錯誤處理機制
目前 WePY 的錯誤處理還比較簡單,沒有一個通用的錯誤處理機制。使用者在使用和編譯時的報錯很難追溯和定位。後面希望能做到在報錯時可以定位到報錯的檔案和程式碼。
-
測試用例覆蓋度
WePY 目前只有核心庫被測試用例覆蓋。CLI 部分很複雜沒有做測試用例覆蓋。這導致目前大部分問題都和 CLI 相關。在下一個版本要全部被測試用例覆蓋。
編譯

上圖是2.0版本編譯部分的對比。左邊是 1.0 的編譯,右邊是2.0正在做的事。前面有講到1.0的編譯是把.wpy 檔案放到 CLI 中進行編譯。CLI 本身涉及編譯器和外掛。在2.0中,將檔案編譯修改為了入口編譯,從 App 入口,通過 CLI 自動解析依賴,CLI 中也只有外掛,所有的核心功能都將通過外掛實現。最後生成的除了小程式檔案,還有 Vendor 檔案(Vendor 檔案是指所有的 npm 包都會打包到這個檔案內)、資原始檔以及自己引用的模組的檔案。
外掛化

編譯的核心部分是參考 Webpack 做的外掛化編譯。外掛化的概念參考我上面做的圖:固定一塊板子,板子上有固定數量的掛鉤,每個掛鉤都可以掛不同的東西。每個掛鉤放什麼不清楚,但是每個掛鉤都可以實現不同的功能。我只需要規定編譯的流程,通過在掛鉤中寫不同的內容實現整個編譯流程。所以整個編譯過程變為:配置初始化➡️核心編譯➡️輸出檔案。
外掛化可以提供更高的擴充套件性和可複用性。所有的核心功能都依賴外掛進行。使用者覺得某個功能不合適的時候,完全可以自己寫一個外掛替換掉核心功能。使用者可以對編譯的任何一個環節進行修改。
資料繫結v1

v1 的資料繫結:在初始化的時候對資料進行深拷貝做資料備份。每個流程都會預置 apply 動作,比如有一個點選事件,點選事件對資料進行修改後進入到 apply 流程,在 apply 流程中進行深比較得到髒資料,髒資料最終進入到 setDate 中。
右邊是比較簡單易懂的圖:小明對檔案 B 進行修改得到 B+,老師將 B+ 和 B 進行對比,得到修改的資料。這是一個同步流程。當小明叫小紅修改 C 檔案時,如果老師不再,需要小紅主動叫老師對 C 檔案進行對比。即手動呼叫 apply 流程。
資料繫結v2

2.0 使用了 Vue 的資料繫結機制。在初始化時生成 Render Watcher,每個資料初始化時都會新增 observer。修改資料時記錄修改的 key-path 並加入佇列中,所有的修改動作都會觸發 Watcher。在一個 nextTick 時間內會清空佇列,並在 Render Watcher 中進行 setDate。setDate 環節根據記錄的 key-path 進行 setDate。
相比小明和老師的故事:小明在修改檔案時會主動記錄修改的內容併發起通知,小紅的操作方式與小明一致。當老師收到通知時,根據小明、小紅的修改記錄對修改的內容進行 setDate 的處理。
這種優化方式不需要手動呼叫 apply,也不需要關心非同步流程。
質量

第二個版本會先在內部專案運用,內部實踐之後沒有問題再開源。另外2.0版本測試用例覆蓋度要完全覆蓋。
開源經驗分享

規範

如何保證開源專案的質量?
第一是文件規範。Readme 部分要言簡意賅的講明這個專案能做什麼,一個簡單的示例說明如何啟動專案。Readme 要簡潔,大家一眼能看到他想要的東西。
第二是 CI。將對應的狀態放在 Readme,讓開發者可以更安心的使用這個專案。
第三是 license。
還有 contributer 文件,程式碼規範、Git 規範等。

測試使用了 Mocha 和 Istanbul,整合使用了 TravisCI,部署使用了 npm 和 lerna。
推廣運營

推廣運營方面主要靠自己發文章,做外鏈。另外我在公眾號和微信群推了自己的文章。微信群做了一個機器人放入群碼。
還做了文件監控,官方文件修改之後,我可以第一時間知道官方文件都修改了什麼。以及監控報告,每天都會給我的微信推送今天專案有多少 star 、多少 issue 。
後期維護

後期維護主要是文件、issue、pr 和新的計劃維護。右邊的圖,灰色部分是我沒打標籤的 issue。下面閉合的是我在相應時間點處理完的 issue,沒有閉合表明這個 issue 還在處理中。

WePY 2.0 目前處於內測階段,10月底會發布公測版本。