用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

凹凸實驗室發表於2018-09-20

大家好,我叫李偉濤,來自凹凸實驗室。今天跟大家分享的主題是用 React 開發小程式的探索之路 。

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

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

第一部分:原生開發之痛

開發小程式由三部分組成,這三大部分都是由四種型別檔案,如下圖所示:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

我們以 JS 檔案為例:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

  • 開發體驗
  • 效能瓶頸

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

  • 避免頻繁 setData
  • setData 避免傳入大規模資料

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

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

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

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

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

JS 程式碼對比:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

生命週期對比:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

模板對比:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

編譯時的處理:

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

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

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

  • 智慧的程式碼提示
  • 健全的錯誤程式碼檢查

第三部分:重生之路

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

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

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

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

最初的版本中,僅僅是對小程式 setData 做了一次非同步封裝,最終呼叫 setData 更新的時候還是傳入了完整資料。

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

之前我們講到過在頻繁的呼叫 setData 和 資料量非常大的時候,小程式就會變得異常卡頓,效能很差。

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

  • 使用小程式第三方框架
  • 與原生小程式進行混寫
  • 更加健全的 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 的使用、開發中,產生了更多更優秀的使用案例。

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

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

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

第五部分:面向未來

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 將聯合各大公司小程式開發團隊,推出豐富的行業模板,為各行業應用視覺化搭建提供完整的解決方案。

完善生態

在開源之初,Taro 一直處於封閉的狀態,沒有適配的 UI 庫,也無法使用第三方元件庫,而這些對開發效率的桎梏非常嚴重,社群內對此反饋較多。所以,我們基於 Taro 推出了首個可以跨多端使用的多端 UI 庫 Taro UI,目前已經支援了微信小程式與 H5 端,不久之後將完成 React Native 端的適配,可以同步提供給 React Native 端使用。

最後,多端統一開發框架 Taro 1.0 正式釋出!

  • 更加健壯的元件化
  • 支援引用小程式第三方元件庫
  • 與原生小程式程式碼混寫
  • 極致的效能優化
  • 更加豐富的 JSX 語法支援
  • 全面支援 TypeScript
  • React Native 轉換支援
  • ……

用 React 開發小程式的探索之路 (演講內容整理)| 掘金開發者大會

相關文章