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

語言: CN / TW / HK

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

本文由 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源創計劃”,歡迎正在閱讀的你也加入,一起分享。