用 React 開發小程序的探索之路

在目前市面上已經有非常多的小程序開發框架,其中的佼佼者如 wepy 以及 mpvue ,他們都是非常優秀的小程序開發框架。但是它們都有一個共同的特點,都是通過類 vue 語法的小程序開發框架。這點對於國內一些 react 的開發者來說就顯得有點遺憾了。

我們團隊在去年就整體轉入了 react 開發陣營,對於我們團隊來說, react 會更加熟悉一些。所以我們一直在探索如何用 react 開發小程序,前端時間我們開源了一個框架,叫做 Taro 。本次也會圍繞這個,來分享 探索使用 react 開發小程序。主要包含以下五個部分內容:

第一部分:原生開發之痛

開發小程序由三部分組成,這三大部分都是由四種類型文件,如下圖所示:

我們以 JS 文件為例:

我們在寫原生小程序的時候,這兩份代碼是非常常見的。 它們都是藉助函數工廠類的方式去構建頁面以及組件。 在小程序中的一大特色就是使用字符串模板的形式來編寫界面,如圖:

以上就是一些小程序官方寫法上的一些約定,但也是這些約定,讓開發者存在一些開發上的痛點,這些痛點主要集中在:

開發體驗性能瓶頸

在開發體驗上,代碼組織稍顯複雜。 當組件和頁面越來越多,項目越來越龐大的時候開發成本就會顯得有點高,其次就是編碼體驗不夠順暢,如下圖:

頁面或者組件無法被繼承的時候,我們在實現一些功能的時候會受到一些限制 ,同時小程序本身提供了一些 API ,但是卻沒有提供一個跟編輯器很好結合的東西,當我們在使用這些 API 的時候缺乏智能提示。 其次就是字符串模板稍顯孱弱。例如 :

當我們實現一個日期格式化的時候,點擊的時候無法傳參,還有就是直接寫一個格式化函數是無法運行的,我們需要藉助 wxs 這樣的一些工具去實現這樣的一個功能,但是這樣是非常麻煩的。 還有就是小程序的代碼規範並不是很統一,以 Button 組件為例:

一些屬性參數都是有很大的差異的。 其次就是缺乏統一的自動化編譯處理,導致無法直接在小程序中直接使用一些 新的 ES 語法,以及 SASS 、 LESS 來書寫樣式代碼。

在性能瓶頸上面,小程序的整體架構是這樣的:

分為視圖層和邏輯層,這兩個層之間是有一個特定的通信方式的,當我們在調用 setData 去更新視圖的時候,小程序首先把你傳入的數據 使用 JSON.stringify 進行序列化,之後拼接成一段可執行的 JS 腳本,最後運行。在這樣的一層通信機制上,導致去調用 setData 的去更新視圖的時候成本非常之高。所以小程序官方也是提供了一些對於性能優化上的提示

避免頻繁 setDatasetData 避免傳入大規模數據

針對以上的痛點和限制,業界也有一些優秀的解決方案,諸如 mpvue, wepy, 但是它們都是類 vue 的開發框架。正如前面所說,這樣子的話對於我們團隊或者使用 react 的開發者有點遺憾。

第二部分:如何使用 React 開發小程序

使用 react 來開發應用帶來的的一些好處:

react 和 小程序是有一些共同特點的

View = F(Data),都是通過數據來驅動視圖模型同時都是用一種類似的 API 來驅動整個視圖的更新 (小程序:this.setData(), react:this.setState() )

正因為這樣,也是更加想用 react 來開發小程序。 經過進一步的研究發現,小程序和 react 之間的差異是非常大的 主要是由於三大塊的差異:

JS 代碼對比:

生命週期對比:

模板對比:

這麼大的差異導致我們想用 react 來開發小程序的難度非常之大,所以我們應該怎麼使用 react 來開發小程序呢? 仔細思考一下我們的需求,我們是希望通過 react 語法的代碼來開發小程序,那麼其中的核心工作就是將 react 代碼通過某種轉換操作,變成小程序可以運行的代碼。這樣一種在兩種語法之間轉換的這種操作其實就涉及到一個編譯原理。 編譯原理的一個大致過程大概如圖所示:

其中最核心的就是把源代碼編譯成 AST (虛擬語法樹),然後將 AST 進行轉換操作得出目標代碼。 在 JS 中,它是有自己的 AST 規範來進行定義,這個規範就是 ESTree Spac

在 JS 領域中,有非常多的 JS 的解析器,來幫你把代碼轉換成語法樹的工具,其中最廣為應用的就是 BABEL。

它提供了一套非常完成的工具來幫你做代碼轉換。 從源代碼到語義分析,我們都可以藉助 BABEL 來進行轉換。 在這之後的語法樹轉換、代碼優化還是需要們自己來進行的,這一部分也是非常繁瑣且複雜。

在 Taro 中,我們通過在編譯時處理以及運行時適配來轉換成小程序代碼,

編譯時的處理:

在 JSX 中,通常有各種各樣的寫法:

這導致在編譯的時候非常複雜,需要做大量的測試用例來保證轉換是正常的。

代碼編譯出來時候,還是不能只在小程序上運行的,小程序需要一個運行時的適配來幫助我們把代碼運行在小程序裡面。 運行時的框架主要是一些生命週期的轉換適配,還有一些事件處理。

僅僅這些是不夠的,如果真正需要投入開發使用還是有點差距的。這個時候我麼你需要一個開發工具來進行配合。

同時,Taro 來提供了一些貼心的功能,來幫助我們獲得良好的開發體驗

智能的代碼提示健全的錯誤代碼檢查

第三部分:重生之路

開源之初,由於種種原因,Taro 的微信小程序端組件化採用的是小程序 <template> 標籤來實現的,利用小程序 <template> 標籤的特性,將組件 JS 文件編譯成 JS + WXML 模板,在父組件(頁面)的模板中通過 <template> 標籤引用子組件的 WXML 模板來進行拼接,從而達到組件化的目的。 實踐證明,Template 模板方案是一個失敗的組件化方案,Taro 開源初期的 Bug 主要來源於此。因為這一方案將 JS 邏輯與模板拆分開了,需要手工來保證 JS 與模板中數據一致,這樣在循環組件渲染、組件多重嵌套的情況下,要保證組件正確渲染與 props 正確傳遞的難度非常大,實現的成本也非常高。而且,囿於小程序 <template> 標籤的缺陷,一些功能(例如自定義組件包含子元素,等)無法實現。

所以,在經過艱辛的探索與實踐之後,我們採用了小程序原生組件化來作為 Taro 的小程序端組件化方案,並且通過一些處理,繞開了小程序組件化的諸多限制,為 Taro 的穩定性打下了堅實基礎,並帶來了以下好處:

小程序端組件化更加健壯儘可能減少由於框架帶來的性能問題依託官方組件化,方便以後解鎖更多可能

其中有個重要的改進,小程序端性能的優化

最初的版本中,僅僅是對小程序 setData 做了一次異步封裝,最終調用 setData 更新的時候還是傳入了完整數據。

之前我們講到過在頻繁的調用 setData 和 數據量非常大的時候,小程序就會變得異常卡頓,性能很差。

Taro 在框架級別幫助開發者進行了優化,在 setData 之前進行了一次數據 Diff,找到數據的最小更新路徑,然後再使用此路徑來進行更新

除此之外,我們還做了更多

使用小程序第三方框架與原生小程序進行混寫更加健全的 TypeScript 支持

第四部分:開源探索

從 開源 到現在,Taro 一共經歷了 1800 餘次提交,平均每天近 20 次,最多的一天達 30 次。每一次提交都是進步,每一次提交都讓 Taro 更加強大。經過這麼多次迭代之後,已經讓 Taro 獲得重生,尤其是小程序組件化重構完成之後,Taro 從舊版架構的泥潭中一躍而出,成為更加健壯的開發框架。 在我們自己不斷反思、優化的同時,也積極融入開源社區,依託社區的力量去建設 Taro。 Taro 到目前為止,一共收到了 500 餘個 ISSUES,已關閉近 400 個,正是因為這些 ISSUES ,讓我們不斷意識到 Taro 的不足,讓我們知道如何去進行迭代。 同時,我們也一直鼓勵社區的開發者積極提 PR,一個優秀的開源項目需要依靠整個社區的力量才能完善起來,到目前為止,一共收到了 120 餘個 PR,已幾近全部合入,這些 PR 為 Taro 注入了許多新鮮血液,讓 Taro 更加健壯,我們也期望能有更多的開發者可以加入進來,一起來讓 Taro 更加美好。 在 GitHub 上交流之餘,我們也為開發者們開通了官方微信群供大家一起討論 Taro 與技術,目前已有超過 1700 位開發者在關注、使用 Taro ,期待更多開發者的加入。

在開源期間,隨著 Taro 的逐步完善,越來越多的開發者加入到 Taro 的使用、開發中,產生了更多更優秀的使用案例。

Taro 的發展離不開廣大開源愛好者的幫助,在此特別鳴謝廣大 Taro 的使用者以及 Taro 主要貢獻者

第五部分:面向未來

Taro 將會繼續保持迭代,目前已經規劃瞭如下重要功能:

便捷測試

在編譯時與運行時提供代碼診斷的功能,分析代碼優劣,判定代碼寫法是否規範,以便幫助開發者規避一些由於寫法帶來的問題。 同時將提供一套測試方案,方便開發者書寫並運行組件測試用例,提升代碼質量。

多端同步調試

目前 Taro 只能一次調試一個端,這對於開發多端應用來說效率略低,所以,計劃提供微信小程序/ H5 / React Native 端同時調試的功能,可以一鍵啟動多端同時編譯,從而獲得多端同步預覽。

微信小程序/H5 代碼轉 Taro 代碼

目前已支持 Taro 代碼到小程序代碼、 H5 代碼的轉換,在未來,將提供逆向轉換功能,幫助開發者將原本就存在的小程序/H5 項目直接轉換成 Taro 項目,從而讓原本只能運行在一端的項目獲得多端運行的能力,降低開發者的重構成本。

與 React 新特性保持同步

Taro 是遵循 React 語法規範的,但是 React 一直在迭代在變化,Taro 作為 React 的追隨者也將會保持與 React 新特性同步,讓 Taro 最大程度接近 React 開發體驗。

快應用端支持

目前 Taro 已經完成了快應用端組件庫與 API 的適配,快應用端的文件轉換與模板轉換也正在開發中,不久的將來就會發布支持快應用端轉換的版本。 支付寶小程序與百度智能小程序支持 已預研支付寶小程序與百度智能小程序轉換的可行性,即將進入開發。

多端可視化拖拽搭建

目前 Taro 是依靠開發者手工編寫代碼來獲得多端應用的,Taro 未來計劃提供一個多端可視化拖拽搭建的功能,可以通過拖拽組件的方式來生成多端應用。 同時,Taro 將聯合各大公司小程序開發團隊,推出豐富的行業模板,為各行業應用可視化搭建提供完整的解決方案。