Taro 在多端浪潮下的選擇與挑戰


作者|朱天健
編輯|賈亞寧

本文由 InfoQ 整理自京東零售平臺業務中心高級前端工程師朱天健在 GMTC 全球大前端技術大會(深圳站)2021 的分享《Taro 在多端浪潮下的選擇與挑戰》。

多端研發對於當今時代的前端開發來說是個繞不過去的話題,爲了解決這些問題,各大公司的開源項目推出的開源框架不在少數,而 Taro 從 2018 年開源至今已經三年有餘,在 GitHub 上收穫了超過 3W 的 Starred,在開源後幫助很多團隊和開發者的同時,我們也通過與社區內萬餘活躍用戶的交流和反饋摸索前進的方向,與諸多開發者一起共建社區,和 Taro 一起成長。

我們需要一個怎樣的多端解決方案
小程序生態共榮

我們到底需要一個怎樣的多端解決方案呢?以 Taro 的視角來說,我們基礎的前提是希望多端不會成爲開發者的障礙,特別是在小程序生態整體上呈現欣欣向榮之勢時,我們期待整個生態都可以繼續成長,與開發者們相互成就。

近幾年來,每隔一段時間就會有很多新的小程序平臺出現,帶來了更多流量渠道的同時,也給開發者創造了很多難題。

小程序平臺

產品同學可以很輕易地喊出“我全都要!”,那麼我們作爲開發可以嗎?不論是 Web 、React Native 端,還是各類小程序平臺,在開發過程中都勢必會牽扯很大的精力。特別是平臺方很多時候也沒有足夠的時間和精力照顧到所有開發者的開發體驗,而同樣對於很多跨端框架的開發者來說,適配一個全新的平臺也勢必不是一件容易的事情。

跨平臺開發是小程序生態持續擴張的重要力量,同時也使小程序成爲互聯網生態快速拓展的核心之一。這就是爲什麼我們期待中的小程序生態需要大家共同建設,每一個新成員的加入,帶來的都不僅僅是流量,更是新鮮的活力,這些都會促進整個生態的繁榮。

開發性能與體驗

但是,這裏就不得不提到但是了!!!代價又是什麼呢?

面對多個平臺同步開發的過程中,我們往往會遇到很多問題,比如:爲了同步多端能力,我們往往很難快速響應業務需求;如果採用原生開發,每增加一個平臺,研發成本都是指數級增長;而開發完成並不意味着任務結束了,維護這些多端同構又具有差異化的代碼的困難程度可想而知。

所以對於開發者來說需要的無非是多端一體化的開發體驗;希望框架在開發維護舒適的同時,還可以擁有卓越的性能。插件化同樣是十分重要的能力,對於很多項目不需要的能力完全可以自主選擇;而對於更多社區的開發者羣體來說,如果有特殊的需求,可以通過定製化的插件去實現,而不需要等待官方響應。

面向開放、開源社區、開發者

本質上我們需要面向開發、面向開源社區中的各個團隊以及其中諸多開發者開放框架的能力。

支持更多框架

我們希望可以讓開發者自由地選擇自己喜歡的框架,不論你是喜歡 React、Vue 還是更多其他的解決方案,都可以不受限制地去使用這樣一個多端解決方案去實現自己的創意,這纔是開源的精神,也是我們做開源項目的目的。

當然這也就有了 Taro 向社區內所有開發者提供的開放式跨端跨框架解決方案

高拓展性的開放式架構

沒有什麼是一蹴而就的,對於 Taro 團隊來說,我們面臨的很多問題也是一樣的。雖然剛剛我們提到了很多,但這些內容也是我們一組一個腳印慢慢實現地。而在最早期的時候,Taro 還沒有這麼開放,它只支持 React Like 的方式去寫小程序,而且還是一個重編譯時的框架。

Taro 架構

就像這個架構圖顯示的一樣,我們通過 AST 解析開發者的 React Like 代碼,轉換成對應端的小程序代碼,通過適配層就可以完成所有小程序的適配。雖然一句話就可以講完我們所有的工作,但是其中的困難很多都難以想象,我們發現維護框架的成本逐漸超出了我們可以接受的極限,所以我們選擇向前再邁出一大步。

插件化架構

不得不說,插件化架構給我們了很大幫助,我們將所有可以拆分出來的東西悉數拆分,幾乎所有的能力都是通過插件化的方式提供,最終也就形成了 Taro 3.x 的框架。

在 Taro 3.x 對整體框架調整之後,大大降低了適配新框架的成本,通過對齊組件和生命週期我們就可以在 Taro 的生態中引入一個新的框架。

Taro 3.x 架構

當然在這個架構中 Web 、React Native 和小程序端的實現略有不同。在小程序中,我們需要注入 DOM、BOM 並提供對應框架的渲染器,最終通過 Webpack 打包給開發者使用;Web 端則是通過 WebComponent 提供了標準化的組件,同時結合標準的路由體系模擬了所有的 API 提供給開發者;React Native 中也是同樣的邏輯,通過 Metro 將標準化的組件和 API 打包給開發者使用。

端平臺插件

插件化架構幫助我們引入了一個新概念——端平臺插件,它幫助我們將每一個端的能力拆分開,插件通過提供編譯時的模板、組件、編譯配置,加上運行時所需的組件、API 和渲染器,將它們分別注入 Taro CLI 和 Runtime 中對應的生命週期,Taro 就能夠轉譯成對應端的代碼。

以微信小程序插件 @tarojs/plugin-platform-weapp 爲例,我們通常會按照如下方式組織項目文件:

├── src                      源碼目錄|   ├── index.ts             插件入口|   ├── program.ts           編譯時入口|   ├── template.ts          模板處理邏輯|   ├── runtime.ts           運行時入口|   ├── runtime-utils.ts     運行時依賴工具|   ├── apis.ts              API 相關處理|   ├── apis-list.ts         API 列表|   ├── components.ts        組件列表|   └── components-react.ts  給 React 使用的組件類型├── types                    類型├── index.js                 編譯時入口├── tsconfig.json├── rollup.config.json├── package.json└── README.md

通過繼承基類 TaroPlatformBase 實現端平臺的編譯,然後在插件入口函數中調用上述自定義平臺類的編譯接口:

// index.tsimport Weapp from './program'
export default (ctx) => { ctx.registerPlatform({ name: 'weapp', useConfigName: 'mini', async fn (arg) { // 調用自定義平臺類的 start 函數,開始端平臺編譯 const program = new Weapp(ctx, config) await program.start() } })}

runtime.ts 是我們運行時的入口文件, Webpack 編譯時會把它注入到 app.js 中進行引用。

// runtime.ts
import { mergeReconciler, mergeInternalComponents } from '@tarojs/shared'import { hostConfig, components } from './runtime-utils'
mergeReconciler(hostConfig)mergeInternalComponents(components)
  • 使用 mergeReconciler 函數把自定義的 hostConfig 合併到全局 Reconciler 中;

  • 使用 mergeInternalComponents 函數把自定義組件信息 components.ts 合併到全局 internalComponents 組件信息對象中。

// runtime-utils.ts
export * from './components'export const hostConfig = {}
// 抽取 runtime-utils.ts 是爲了方便其它插件引用

參考 @tarojs/plugin-platform-weapp 插件我們可以快速註冊一個其他端的小程序插件,橫向拓展自定義所需的組件、API、渲染器和運行時。當然也可以此爲基礎縱向拓展一個平臺插件,這樣可以快速完成相似的小程序平臺插件開發。

當然整個插件架構的設計並不僅僅是用於構建端平臺插件,各類插件都能很好地完善 Taro 生態,提供更好的開發體驗,社區內很多開發團隊或者個人都提供了非常有意思的插件用於各種研發場景,歡迎大家體驗。

跨框架適配

想要適配框架對於現在的 Taro 來說,並非是一件非常困難的事情,因爲 Taro 提供了自己模擬的瀏覽器環境。

Browser Object Model
模擬瀏覽器環境

作爲瀏覽器環境的基礎,BOM 和 DOM 相關的 API 是必不可少的,這也是供各類前端框架在小程序中運行的根本。

Taro Runtime

Taro 通過模擬這些 API 構建了自己的運行時環境,將所有的事件和節點方法在小程序環境中以對齊 Web 標準的形式呈現。

以基礎的 click 事件爲例,當小程序中 tpl_text 節點觸發事件時,框架會通過 Taro DOM Tree 提供的 getElementById 方法找到 text 上的 onClick 方法找到相應的事件並觸發。

同樣冒泡機制也是事件中重要的組成部分,所以在父級節點 tpl_view 上的 onClick 方法同樣會被觸發,這時就需要通過調用 stopPropagation 方法來阻止事件的傳播。

框架兼容

在完成瀏覽器環境的構建之後,兼容各類框架相對就容易很多,通過 Taro 提供的標準事件將框架的生命週期和小程序關聯到一起,就能夠讓開發者在使用時有更順滑的體驗。

首先要做的就是掛載入口,將構建好的 DOM 樹在小程序觸發 onLaunch 事件時掛載上去,當然每個框架有自己的寫法,比如 React 中是 render Vue 中是 $monut 方法。

緊接着我們需要掛載頁面,在頁面觸發 onLoad 時爲頁面注入 ref 等信息,並將頁面渲染呈現。而每個頁面都會有屬於自己的 pageId,這也使得我們可以將所有的生命週期和每個頁面一一對應,在合適的時機觸它們。

<!DOCTYPE html><html><head>  ...</head><body>  <div id="app">    <Page ref={pageId} />    ...  </div></body></html>

當生命週期對齊,頁面只要渲染出來就可以了,當然這裏每個框架會有些不同。以 React 爲例,ReactDOM 作爲渲染器,功能非常豐富,但包體很大而且並非所有都在小程序中需要用到,選擇使用 react-reconciler 自定義渲染器精簡是個很容易做出的決斷,加上 hostConfig 注入對應的依賴, taro-react 就完成了。

適配 React 自定義渲染器

在運行時中通過 createReactPage 就可以創建 Taro DOM Tree 並通過 setData 和模板交互數據完成渲染。

適配 React 渲染流程

在 Taro 中使用 Vue 也是一樣的,通過調用 createVuePage 創建 DOM Tree 之後就可以實現打通整個流程。

適配 Vue 渲染流程

當然大家如果使用 Taro 支持新框架時,可能會遇到一些問題,比方說 DOM/BOM 相關的 API 缺失或者功能錯誤等等,可以通過 issue 反饋,我們會動態拓展。

跨端適配

對於 Taro 來說端有很多,小程序端、React Native 端、Web 端、快應用端,其中很多都是社區幫助完成適配的。在這裏我們以小程序端爲例,Taro DOM Tree 在渲染的過程中根據不同的小程序平臺其實是會有所不同的,但都是基於 template 組件提供的渲染方法。

渲染方案 3-1

通過模板的一一對應,我們就能完成所有組件的渲染,但不同平臺的模板功能是差異化的,有的支持遞歸,而有的並不支持,這也就分成了兩種不同的小程序類別。比方說阿里、頭條、百度的小程序都支持遞歸,我們可以讓模板自我調用來避免重複。

渲染方案 3-2

而微信、京東、QQ 小程序不支持,我們則會創建新的模板。不支持遞歸的模板模式當然有可能會存在一些問題,比方說模板文件過大,但我們可以通過設置 baseLevel 配置合理優化遞歸層級數;同樣因爲自定義組件樣式會有影響,避免嵌套也是一個優化的方案。

渲染方案 3-3

Taro 的支持跨端一直以來都走在業內的前沿,雖然大家可能更熟悉的是我們支持微信、京東、阿里、百度、頭條和 QQ 小程序,以及 Web 、React Native 和快應用端這些,但其實 Taro 社區內提供的平臺遠不止於此。

小程序

不知道你是否嘗試使用 Taro 編譯快手、芒果、飛書,甚至是支付寶 IOT 小程序呢?這些新增的平臺有些是官方的小程序平臺提供,也有很多其他公司的團隊或者個人開發者根據自身的業務需求開發提供的,當然也期待可以在社區中看到更多大家編寫的 Taro 平臺插件。

小程序和 H5 的生態融合

說起小程序和 H5 的生態融合,不知道大家會想到什麼呢?可能也會困惑什麼是生態融合?Taro 爲什麼要做生態融合?又是怎麼做到生態之間的融合呢?

什麼是生態融合?

Taro 已經支持了這麼多小程序平臺,同時也支持了 H5 端,那麼是不是大家都使用了 Taro 框架,小程序端和 H5 的生態就可以融合起來呢?顯然不會是。

在各個不同的小程序生態之中沉澱了大量專屬的小程序插件,如果開發者想要使用 Taro 的同時直接利用這些專屬的原生小程序能力可以麼?這顯然不會有任何問題能形成阻礙。

那麼原生小程序能不能通過 Taro 轉換成 H5 應用呢?通過 Taro 的 convert 指令你就可以完成原生到 Taro 項目的過程,Taro 可以幫助你轉換到任何平臺去使用。

npx @tarojs/cli convert

那麼這就夠了麼?我有一個原生的項目可不可以使用 Taro 編寫的組件呢?有同學可能會說 Taro 可以編譯小程序插件的,你導出插件就可以在原生應用使用 Taro 。但實際上 Taro 同時還提供了 blended 指令,可以將 Taro 項目編譯到指定平臺,供原生小程序或者其他端的應用集成使用。

taro build --type weapp --watch --blended

除此之外還有嗎?Taro 可不可以直接在小程序使用 web 組件呢?

使用 HTML 標籤

仔細思考一下,這件事情完全是可以的!所以我們新增了一個插件 @tarojs/plugin-html 來完成這件事情。

實現這個插件籠統地說,我們的任務主要劃分爲三個方向,分別將標籤名、屬性、組件映射就可以了,當然實際上還是會遇到很多問題,但這是有價值的,特別是它在社區內有很高的呼聲。最重要的原因就是我們可以通過這個插件直接在小程序中使用 web 端的各種工具,特別是一些組件庫,我們可以直接在 Taro 中使用而不需要特別考慮跨端的問題。

比如 Ant Design、 Vant 以及 WeUI 我們都提供了 demo 給到社區可以直接使用,這將進一步打通 Web 端和小程序端的生態壁壘,同樣很多老項目都可以直接在小程序端直接運行,也會是一個很大的便利。

小程序使用 web 端生態

當然這並非毫無限制,比方說 DOM API 會有一些差異:

  • 小程序部分 API 不支持同步調用

  • 小程序部分組件 API 需要通過 Context 調用

同樣一些特殊的用法,包括部分標籤節點,在使用時也存在一定的差異:

  • 不支持在 DOM Tree 之外插入節點(React 的 Portal,Vue3 的 Teleport 都是不支持的)

  • ReactDOM 功能精簡(Taro 使用 react-reconciler 自定義調試器)

  • 小程序不支持部分樣式或 CSS 選擇器(默認寬高並非原圖寬高)

  • 小程序不支持 svg

更多限制細節可以參考官網上的相關文檔。

鴻蒙帶來的機遇和挑戰

Taro 也能支持鴻蒙嗎?這是我在很多社區的交流羣中聽到最多的一句話,但其實 Taro 支持鴻蒙是可行性非常高的,畢竟 OpenHarmony 的 JS UI 語法和小程序的相似度很高。所以其實早在鴻蒙第一次曝光時雙方的團隊就有過很多深入地交流,並探討過相關的可行性,當然一直到近期我們纔有足夠的人力去完成鴻蒙平臺的適配。

Taro 和華爲以及開放原子基金會都多有合作,但是總結下來就是 Taro 即將加入 OpenHarmony 併成立 CrossPlatformUI Sig,爲鴻蒙提供跨端能力的支持。

鴻蒙帶來的機遇和挑戰

對於 Taro 來說,我們同樣可以通過插件的形式適配鴻蒙,將它作爲一個平臺橫向拓展就可以完成鴻蒙的接入。

當然爲了抹平鴻蒙和其他平臺的差異,我們需要針對處理的問題還有不少,比方說支持 React&Vue 語法,支持標準的組件和 API 等等,支持語法通過編寫框架的運行時就可以實現,而組件和 API 則需要通過 OH 提供的能力來實現。

最終就可以看到我們寫的代碼可通過 webpack 打包成應用,在前端框架層通過 Taro 提供的運行時與 UI 視圖交互數據和事件,加上 OH 提供的基礎能力就可以爲鴻蒙端適配渲染。

Taro 適配 OH 的渲染流程

Taro for Harmony 相關的能力將會作爲 v3.5 版本的特性發布,目前 canary 版本已經發布,歡迎大家踊躍嘗試,我們也會和社區諸多開發者們一同持續完善相關的能力,並提供支持。

總結和展望

最後的最後,關於 Taro 還在做的事情其實還有很多,我們在這裏簡單地總結展望一下。

Taro for Harmony

首先是就 Taro for Harmony,剛剛其實也有提到,我們很快會發布正式版本,目前正在邀請社區的同學進行內測當中,正式版本發佈時間,我們預計會在 2022 年 3 月份,大家感興趣可以關注,當然也可以通過小助手加入 Taro 的鴻蒙交流羣,獲取更多的信息。

跨平臺測試

跨平臺測試一直以來都備受社區開發者們的關注,我們其實在內部已經有兩套方案持續迭代當中,只是由於很多原因一直沒有開源出來給大家使用。

沙箱測試

測試沙箱作爲一套自研的方案,可以完全適配全平臺的小程序和 Web 端的邏輯測試,通過模擬小程序的 DOM 結構、生命週期和 API 來輔助開發者完成小程序相關的能力測試;在 Web 端則是通過解析生成代碼的 AST 獲取應用和 Taro 實例,結合 Jsdom 模擬實際的瀏覽器環境,達成和小程序一致的測試體驗。

自動化測試

另一個方案 TIga 則相對更真實,通過 puppeteer 和小程序官方提供的接口在瀏覽器環境或者小程序官方平臺提供的測試環境中完成 UI 測試,目前支持了 Web 端和微信小程序,在內部項目的使用中也廣受好評。兩個方案各有側重,希望有一天能夠開源,與社區的開發者見面。

Cloud IDE

Cloud IDE,也就是 Tide 項目,也傾注了我們團隊很多成員的心血,通過內置的 Taro 研發流程,很好地解決了在小程序開發過程中的諸多癢點,比方說模板、插件管理,多端配置差異,版本管理等等工程化的問題。

Cloud IDE

在大型小程序項目中產品、設計、研發和測試之間的團隊協同;同時通過內置的小程序模擬器,避免了調試中窗口反覆切換開發者工具模擬器;小程序測試上線流程、線上環境監控……這些目前在內部使用的反響都不錯,很好地幫助我們解決了很多團隊內的問題。

文末回答兩個大家關心的問題:

  1. Taro3 性能優化的方向

其實會上也有同學提到關於 Taro 在 3.4 版本推出支持了 preact,確實不論是 Taro-react 還是支持 preact 都是 Taro 在壓縮包體積方案中做出的嘗試,同時我們也打算通過 wasm 來提升 Taro3 在小程序中的性能。雖然 Taro3 目前還沒有官方的 benchmark,但也在籌備當中,敬請期待。

  1. Taro3 的後續版本規劃與 Taro4

對於 Taro4 目前還無可奉告,但是在 Taro3 的後續版本特性,可以關注我們對外開放的 Task List,並對當前的 Feature Request 投票,對於很多開發中的新特性在這裏都能看到,當然大家如果什麼想法也可以在這裏提交,如果希望參與一些特性的研發工作,也歡迎大家提交 PR。

作者簡介
朱天健
京東零售平臺業務中心 高級前端工程師

2019 年作爲講師出席第二屆軟件綠色聯盟「構生態·建未來」開發者大會,2020 年受邀參加第四屆 TLC 騰訊直播大會。作爲 Taro 框架的核心開發成員,主要負責多端組件庫及 API 相關的研發工作,同時負責開源社區管理機器人羣控系統;Tide 項目的核心開發成員,主要負責 tide-site 和 cloud ide 相關的研發,第三方調用協議和相關接口,以及 Taro 相關的生態插件等。

活動推薦

2022 年 6 月 10-11 日,GMTC 北京站將與您再度相約!本次大會以“業務至上,效率爲王”爲主題,涵蓋前端性能優化、IoT 動態應用開發、TypeScript、移動端性能與效率優化等 15 個前沿技術專題,點擊底部【閱讀全文】直達大會官網,更多精彩內容持續打磨上線中。大會門票 7 折限時優惠,立減 1440 元!感興趣的同學聯繫票務經理:17310043226。

本文分享自微信公衆號 - 凹凸實驗室(AOTULabs)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章