美團民宿跨端複用框架設計與實踐

從 PC 時代、移動時代到萬物互聯的 IoT 時代,伴隨終端設備的日趨多樣化,跨端複用的種子自此落地,開始生根發芽。從業務角度出發,跨端技術演進更可能是在不一樣階段、不一樣時間段內業務效率上的選擇,美團民宿業務在大前端融合的浪潮中逐浪前行,不斷探索和迭代抉擇,爲解決業務痛點而孵化出跨端框架技術,在這個過程當中,咱們進行了不少的探索和實踐的思考,但願能給你們一些啓發。本文主要分享美團民宿在跨端複用技術探索和業務實踐過程當中的經驗。

從 PC 時代、移動時代到萬物互聯的 IoT 時代,伴隨終端設備的日趨多樣化,跨端複用的種子自此落地,開始生根發芽。從依靠容器能力、各種離線化預裝包的 Hybrid 方案,到經過 JSC 鏈接 JavaScript 生態與原生控件,結合視圖框架(React、Vue等)尋找效率、動態性和性能更均衡的 Native 容器方案(React Native、Weex 等),接着由微信牽頭的以多進程 WebView、容器標準化的小程序方案出世,各平臺小程序隨之春筍萌發,隨後帶來了國內Taro、uni-app、Rax、Remax等多端框架的百家爭鳴。前端

從業務角度出發,跨端技術演進更可能是在不一樣階段、不一樣時間段內業務效率上的選擇,美團民宿業務就是在大前端融合的浪潮中逐浪前行,不斷探索和迭代抉擇,爲解決業務痛點而孵化出跨端框架技術。本文主要分享美團民宿在跨端複用技術探索層面以及業務實踐過程當中積累的經驗,但願能給你們帶來一些幫助或者啓發。node

1. 背景

1.1 美團民宿業務介紹

美團民宿專一爲消費者提供「住得不同」的旅居體驗,提供的服務包括民宿、酒店、公寓、客棧、短租、賓館、旅行住宿等,同時包括樹屋、房車、INS 風等新奇的網紅民宿。美團民宿自上線以後,業務發展迅猛,在供給側,房源類型不斷豐富,各種分銷、直銷、直連、境外陸續推出,房源信息維度不斷擴展,篩選、推薦、信息呈現也不斷變得複雜。同時伴隨着營銷方式的豐富、房東管理、經營、服務的不斷擴充,民宿的業務也愈來愈複雜。美團民宿大前端伴隨業務的發展不斷自我迭代,移動端總體架構也隨之不斷調整、升級,以尋求匹配業務多樣化、複雜化的發展訴求。react

1.2 美團民宿移動端現狀

業務的發展和跨端複用技術的不斷演化,讓美團民宿客戶端從業務剛起步的單端 Native App,到跨 App(民宿 App、美團 App、點評 App )的 Native 複用和以 SSR 彌補性能差距的 Hybrid 的結合方案,在這場性能和效率的博弈中,客戶端最終落腳以 React Native(如下簡稱 RN)爲核心的複用框架。在此同時,民宿小程序端也隨着微信小程序的誕生、生態壯大、多平臺化的趨勢不斷成長,逐漸造成多平臺複用的小程序架構。git

圖1 美團民宿移動端原始架構圖

上圖是美團民宿移動端原始架構圖,左側是客戶端的技術架構,iOS 和 Android 系統層之上是獨立的 Native 基建層,再往上經過了 RN 打開雙端的複用之門,接着以 RN 容器標準化屏蔽了宿主應用間差別,保障了容器化的一致性,進而實現了業務層的複用和跨 App 的複用。右側是民宿小程序當前簡化的架構圖,咱們在基建層作了多端適配,經過多平臺複用構建工具實現了各平臺小程序的複用。當前客戶端和小程端相關獨立,開發維護也相互獨立,團隊各司其職。github

儘管美團民宿 App 已經經過 RN 實現 iOS 和 Android 的跨端複用,可是因爲 App 和小程序仍然須要投入雙倍的人力成本進行業務迭代,因此咱們思考一個問題:是否能夠更進一步,使用一套代碼解決多端,把 iOS App、Android App、小程序進行大一統。算法

2. 美團民宿跨端複用框架設計

2.1 行業現狀

近幾年,在微信小程序產品牽頭下,業界也隨之誕生出各類小程序應用,各端技術差別使得開發和維護成本都成倍增長。爲了抹平原生開發、小程序開發、Web 開發等技術差別,一些優秀多端框架也就此誕生了。好比 Taro、uni-app、Rax、Remax 等,這些框架都是以自身定義 DSL (通常是 React DSL、Vue DSL)轉換成各端應用(微信小程序、RN、H5等),從而實現一套代碼,多端運行。小程序

在美團民宿業務中,App 的交易佔比較大,從業務角度出發需優先保障 App 的性能體驗和需求開發效率,而當前的民宿 App 已遷移至 RN 技術棧。基於這兩點,咱們但願跨端複用方案的是: RN 轉到小程序平臺方案,因此上述的多端框架並不能知足咱們的 RN-小程序跨端複用的訴求,爲此美團民宿參考了業界多端設計方案,實現了基於 RN 轉小程序複用的方案。後端

RN 採用的是 React 語法,所以如何將 RN 轉換爲小程序,首先要思考如何將 React 代碼轉換成小程序可運行的代碼(簡稱小程序代碼),其次是 RN 基礎組件庫的適配。隨着這幾年的發展, React 代碼轉換成小程序代碼在業界實踐也是層出不窮,業界方案分爲編譯時與運行時兩類,如下是這兩類方案的簡單對比:微信小程序

框架分類 重編譯 重運行
典型表明 Taro2.0 / Rax 編譯時 Taro Next / Remax
原理 編譯時將 React 代碼直接轉換成小程序代碼 運行是經過 React 自定義渲染器完成頁面繪製
優點 性能損耗低 無語法限制
劣勢 語法限制大 性能損耗大

對比來看,重編譯方案有一個嚴重的問題:語法限制。由於大部分前端開發者們已經對靈活的語法有必定的依賴性,好比會使用高階組件、在條件判斷的時候寫不少 return 等等,這種寫法很難在編譯過程被準確命中。所以,編譯時方案就會制定一些語法規則來限制開發者的寫法。重運行方案則沒有語法限制問題,能夠隨意使用各類 React 特性。它的實現原理是經過 react-reconciler 實現小程序平臺對應的 React 渲染器(如下簡稱 MP-Renderer),從而來渲染虛擬 DOM 樹。不太小程序沒有 DOM API 能夠更新界面,因此生成的虛擬 DOM 樹數據是經過小程序的 setData 觸發渲染層的更新,在渲染層裏有一個通用模板能夠用來渲染這些數據。安全

因重編譯語法限制的問題,咱們決定採用重運行時方案來實現 RN 轉小程序。但重運行方案存在性能問題,難以知足業務的要求,咱們經不斷探索後設計了對應的方案極大提高了性能,下文會詳細描述如何解決這個問題的。

2.2 總體方案設計

2.2.1 RN 與小程序複用的技術方案

圖2 RN與小程序複用技術方案圖

總體架構分爲兩個部分:編譯過程、運行過程。它的渲染方式與上文描述重運行時方案相似,都是經過 MP-Renderer 來處理 React 代碼。下面咱們來簡要分析這兩個過程:

(1) 編譯過程:該階段對 RN 源碼進行必定的轉換處理,用於運行過程,編譯後主要產生有如下產物:

  • 編譯後的 RN :通過編譯後產生 RN 代碼,本質上仍是 React 代碼。
  • 適配組件庫:RN 基礎組件的適配庫,是使用小程序自定義組件實現的。
  • 通用模板:因爲小程序沒有像 Web 有 DOM API 操做節點操做方法,因此這裏經過一個通用模板來渲染 React 渲染出來的 TreeData (頁面虛擬 DOM 樹序列化後的 UI 數據)。
  • 合併模板:主要用於性能優化的,下文會詳細分析這個模板的做用。
  • WXSS:將 RN 代碼的 Style 轉換爲 WXSS,這樣能夠減小頁面的 TreeData 數據量,從而優化性能。

(2) 運行過程:運行過程分爲邏輯層和視圖層兩部分。

  • 邏輯層:編譯後的 RN 源碼包含 RN 業務組件和適配組件庫,適配組件庫是經過小程序自定義組件來進行適配。這樣的方式既能夠靈活使用小程序原生代碼對齊 RN 組件功能,也能夠提高轉換後小程序的性能,由於小程序原生代碼不會產生 TreeData 數據,從而使性能上獲得提高。邏輯層有一個 MP-Renderer ,實現方式和上文講述的是同樣的,RN 代碼通過渲染後,便產生對應的虛擬 DOM 樹,虛擬 DOM 樹數據再通過序列化便產生對應的 TreeData(描述頁面的 UI 數據)。
  • 渲染層:當頁面須要更新的時候,邏輯層經過 setData 將 TreeData 傳輸到渲染層裏,TreeData 與通用模板、合併模板和對應樣式結合在一塊兒,即可以渲染出對應的 UI。

綜上所述,上述總體設計與業界多端框架有點相似,可是也有不一樣點,主要體如今適配組件庫和合並模板。適配組件庫上文有解釋比較好理解,而合併模板這裏可能你們仍是比較有疑惑的。其實這個合併模板內容是由編譯過程的 「靜態編譯」 轉換生成的,這樣的處理方式是爲提高轉換後的小程序性能,接下來,咱們會着重來說述這個性能解決方案。

2.2.2 性能解決方案

重運行時方案性能損耗緣由是什麼?正如上文所說,重運行時方案會將全部 React 代碼對應的 TreeData,再經過小程序 setData 傳輸到渲染層,當頁面初始化或者大數據更新的話,setData 就須要傳遞比較大的一個數據,所以也就會形成對應的性能問題。因此要解決這種方案的性能問題,核心就是要減小 TreeData 數據量。

在上述 RN 轉小程序方案,有提到適配組件庫、樣式轉換等是能夠起到對應性能優化做用的,它的優化原理正是經過減小 TreeData 數據的方式。儘管這些方式能夠優化性能,可是在頁面比較複雜的時候,TreeData 數據量仍然會保留比較大,所以優化效果並不明顯。爲此,咱們思考一種新的方式來進一步壓縮 TreeData 的數據量,也就是前文所提到的結合靜態合併樹節點方案,在講述該方案前咱們先來看下一個 RN 代碼轉換爲 TreeData 的例子:

圖3 RN代碼轉換TreeData示例圖

如上圖所示,RN 代碼轉換後的 TreeData 是一個描述 UI 樹的 JSON 數據,等同於右側的 UI 樹,將這顆樹的節點進行分類,能夠分爲靜態數據和動態數據,好比 View、Text 節點就是靜態數據,而 「Hello」、「World」 則是動態數據。所謂靜態數據,就是編譯過程可預知的,所以這些數據是否是能夠轉換另外一種形式來描述 UI 呢,從而減小 TreeData 的數據量。答案是確定的,靜態編譯合併樹節點正是經過這樣的原理來實現的,以下流程所示:

圖4 靜態編譯合併樹節點原理圖-1

這個方案有兩個動做,分別是靜態編譯和合並樹節點,靜態編譯就將 RN 代碼的轉換成合並模板,如上圖序號 2 代碼所示,合併模板的名稱爲 「b1」,內容就是一段與 RN JSX 代碼對應的 WXML 結構片斷。而合併節點是將已經靜態編譯的節點進行合併,如上圖序號 2 至序號 3 流程所示,本來五個節點被合併到頂層的 View 節點,這個 View 節點稱爲合併節點,合併節點須要記錄合併模板的名稱和相關的動態數據,目的是爲了渲染時讓合併節點能夠找到對應的合併模板進行渲染,通過這樣合併節點後,最終生成的 TreeData,如上圖序號 4 所示。能夠看到 TreeData 相比以前的數據量就減小了 60% 左右!

看到這裏,是否是有同窗就有疑問了,上文不是提到靜態編譯會有語法限制,那這裏是否會有語法限制?確實,若是是徹底靜態編譯,是會有語法限制,而這裏所說的結合靜態編譯是有選擇性的編譯,即在編譯過程,首先會經過 AST 分析節點是否靜態數據,若是是的話,再轉換成對應的合併模板。若是遇到不可預測的動態節點,則按照運行時方案去處理。所以,最終生成的 UI 樹節點即會包含合併節點、也會包含本來的組件節點,以下圖所示:

圖5 靜態編譯合併樹節點原理圖-2

經過這樣的方式,既能夠保證語法無限制,又能經過編譯結合的手段最大化優化性能。固然了這種方案也是有缺點,由於這種方案實際上是用空間換性能的方式,生成的合併模板會影響會影響包大小,不過對於一些須要追求性能的頁面,這點包大小的增長是值得付出的。

爲了更好地衡量解決方案對性能的提高程度,咱們參考 Taro 官網的實驗(實驗內容),對優化先後以及原生和 Taro 3.0 運行後的性能指標進行採集與比較。通過實驗,統計出各框架在初始化、加載數據、加載大量數據的操做耗時,以下表所示:

操做耗時 \ 框架 優化前 優化後 原生 Taro 3.0.17
初始化(首屏渲染時間) 897ms 423ms 210ms 675ms
加載普通數據(20條) 1124ms 198ms 110ms 640ms
加載大量數據(400條) 5330ms 1041ms 470ms 3919ms

從上表中能夠看出:性能優化後,得益於更少的渲染數據與更精簡的節點樹,加載數據的操做耗時比優化前減小 80% ,初始化耗時減小了 52%。與同類型的框架 Taro 3.0 相比,也有更好的性能表現。

與原生相比,優化後性能差距明顯減小,可是因爲運行時方案相對於原生須要更多的 setData 數據開銷和更復雜渲染流程,因此從原理上運行時方案和原生性能差距客觀存在。儘管如此,業務實踐上二者差距並不會那麼明顯,由於在測評實驗中測試數據比較純粹,setData 數據使用率較高,但在業務實踐中原生開發 setData 數據不免冗餘且難以優化,而運行時方案會默認優化冗餘數據使得二者性能差距更接近,從咱們歷史業務實踐數據上看,性能與原生差距在 10% 左右。

3. 美團民宿跨端複用實踐

在跨端複用探索中,咱們用創新的方案解決了性能和特性限制的難題,設計了 RN-小程序跨端複用框架。雖然跨端複用屬於「利器在手」,可是這是一把「雙刃劍」,用得其所則事半功倍,處理不當則隱患叢生。那麼,如何在業務實踐中駕馭好這把利刃呢?咱們先介紹在業務實踐中遇到的問題,而後介紹解決這些問題的方案。

3.1 跨端複用場景下的問題

  1. 複用場景下的問題:小程序產品形態以輕、快、便爲旨,用戶可快速使用,用完即走,客戶端產品相對全、精、穩,能夠知足更多的用戶需求,以用戶留存、用戶認知、用戶體驗爲主,二者在產品功能上存在較大的差別,如何恰當地處理產品差別化問題是跨端複用的場景下的一個重要挑戰。
  2. 跨端複用質量隱患:實現了複用便要考慮兩端的各類兼容性問題,這就會產生各類質量上的隱患。如何在複用組件不斷迭代中,保障組件接口、輸入、輸出的兼容性問題?如何保障各個複用組件底層依賴的統1、適配層接口的統一?雙端複用場景下,如何更好的作測試和監控?雙端同窗存在各自技術認知的邊界,如何在出現問題時快速排查、及時止損?
  3. 跨端複用流程規範問題:新的技術革命,必然打破舊的秩序,在當前跨端複用場景下,各類包括工程管理、代碼規範、分支管理、需求同步的問題也會孕育而生,同需解決。

3.2 跨端複用應用架構

爲了解決跨端複用在業務實踐中遇到的各類問題,咱們從新設計了跨端複用應用架構,從架構分層管理、複用方式設計、流程規範、質量保障方面入手,重點解決跨端差別化、質量隱患、流程規範各類問題,並尋求複用的最大化和性能上的均衡。

3.2.1 跨端複用應用架構演進

在這裏,先貼出動態的架構演進過程,讓你們有一個宏觀的認識。咱們先簡單地描述下演進過程,後續會基於最終的架構圖再作詳細的介紹。大體演進過程以下:

圖6 跨端複用架構演進動畫圖

  • 起初,客戶端分 Android App 和 iOS App 單獨開發,引入 RN 技術實現了 Android 和 iOS 跨端複用,可是小程序端依然須要單獨維護迭代。
  • 爲了跟進一步實現 RN-小程序跨端複用,咱們接入了自研的 RN-小程序跨端複用框架,並基於框架的適配規範,以 RN 的基建爲基準,打造出一個和 RN 基建統一接口的小程序適配層。
  • 完成小程序渲染器接入(MP-Render)和小程序適配層後,React-Reconciler 這一層就能夠打通到小程序側,實現了 React 代碼複用到小程序的能力。
  • 實現 RN 與小程序間的複用後,就能夠對存量的 RN 代碼進行抽象、適配、整理,進而抽取出一個組件複用層,這個複用層可直接供上層業務層直接使用。
  • 最後,爲了解決跨端複用場景下各類流程、協做和質量隱患,咱們配套了相應的流程規範和質量保障措施。

3.2.2 跨端複用應用架構總體介紹

圖7 跨端複用應用架構圖

整個民宿的 RN-小程序跨端複用架構圖如上,咱們按照從下到上,從左到右的視角進行解讀:

  • 系統層:最底層是系統服務,除了 iOS 系統和 Android 系統外,咱們把小程序視爲一個單獨的系統模塊。
  • 基礎服務層:系統服務之上是基礎服務層,這一層主要是集團基於 Native 和小程序建設的基建,全公司通用,覆蓋了研發工程中方方面面的基礎服務。在此基礎上,咱們在小程序基建中引入了基於 react-reconciler 實現的小程序運行時渲染器(MP-Render),這個渲染器能在運行時動態更新 vnode 以匹配編譯轉化的小程序 UI 模板,調用小程序原生 API,最終渲染出小程序組件,有了這個基於 React 的小程序渲染器便使得跨端複用成爲可能。
  • 基建層:基礎服務層之上是基建層,這塊主要包括 MRN 基建和小程序適配層,咱們以 MRN 的基建爲標準,適配出一個統一標準和統一接口的小程序適配庫,經過這一層適配,上層能夠無感知、無差別地以同一標準實現複用組件。其中適配層分爲 2 塊,下半部分主要適配 RN 基礎服務,上層是民宿業務獨立封裝的基礎庫和第三方庫,這塊咱們單獨引入一個名爲 Mapping 的適配庫。一個獨立的適配庫可讓 RN 和小程序在業務迭代和技術變革過程當中相互獨立,互不干擾,如此就能保障技術的推動徹底不會影響業務的迭代。基建層的最上方是 react-reconciler,React 框架自己就是把協調過程和渲染過程分開的,react-reconciler 是實現跨端複用的核心,因此咱們把它單獨展現出來,它真正打通了客戶端和小程序的隔閡,只要有了一個獨立的小程序渲染器,就能夠全面、無限制的把 React 代碼複用到小程序。
  • 複用層:基建層再往上是複用層,複用層主要以組件維度作複用,複用組件是基於存量 RN 組件作抽象和適配,而後抽取獨立出來,複用層的組件以統一的標準和接口供上層業務使用。複用層是很重要的一塊,好的複用機制能幫助咱們解決前面提到的產品差別化問題和複用最大化問題。這塊咱們單獨放到 3.3 跨端複用方式設計 來詳細講解。
  • 業務層:複用層之上就是業務層,業務層的各模塊主要以頁面容器來承接複用組件,基於不一樣的端和產品差別,能夠靈活、動態配置頁面的組件來滿意業務的差別化需求。

3.3 跨端複用方式設計

差別化問題,一直是跨端複用場景中的一個痛點,雙端的產品上、平臺上、代碼上的差別如何妥善的處理、適配,也是咱們一直思考的問題。而好的差別化處理方案能夠提高代碼的可維護性、下降質量隱患、提高開發效率。咱們從複用設計層面出發,探索出頁面複用模式、組件複用模式、「組件+邏輯複用」模式等三種複用設計方式,而且根據不一樣的場景下采用不一樣的複用模式,能夠較好地處理跨端差別化問題,同時能兼顧效率提高、性能體驗和可維護性。

3.3.1 差別化下的複用方式

咱們自研的複用框架提供兩種複用模式,以下圖所示:

圖8 小程序複用方式原理圖

頁面複用模式:頁面模式基於頁面維度的,能夠直接把頁面的網絡層、邏輯層、數據層以及頁面內的組件集所有轉換複用,這樣能夠達到複用的最大化,代碼複用率能達到 90% 以上,人效提高明顯。
組件複用模式:組件模式是基於組件維度的,複用以頁面中的業務組件爲目標,把頁面的全部組件抽象、解耦、規範化以後抽取爲複用組件。組件模式只能複用組件內代碼,對於頁面容器的邏輯交互、網絡層都須要小程序本身實現,代碼複用率相對較低,可是組件複用更靈活、可控,可隨意插拔、拼接、定製。

如下是兩種複用模式的優劣分析。

頁面複用模式

優點

1) 提效明顯:整個頁面包括全部組件、頁面邏輯層網絡層一併打包轉換複用,代碼複用率極高,開發效率提高幅度更大。
2) 接入成本低:整個頁面直接轉化同步複用,無需小程序同窗協助接入,減小雙端協助、接口溝通帶來的出錯風險。

劣勢

1) 靈活性低:業務差別和小程序特性不易處理,雙端差別適配只能在 RN 上作,代碼易出錯,維護成本高。
2) 性能劣勢:總體頁面由 RN 轉換複用而來,頁面一次性渲染,性能上會略差一些,並且作頁面級的性能優化困難。
3) 包大小風險大:整頁複用狀況下包大小較大,且不能動態調配(好比頁面內某一模塊需求迭代較少,不想複用,可是頁面模式作不到動態移除)。

組件複用模式

優點

1) 輕便靈活:組件如插件般可隨意插拔、拼接、定製,可較好解決 App 和小程序雙端的差別性問題,針對差別點雙端能夠獨立實現,提升項目的可維護性。
2) 性能較好:頁面容器依然是小程序原生組件,如滾動、滑動組件採用原生可減小性能損耗,另外組件分佈式 setData 渲染有更好的性能,不會像整頁一次性渲染致使 setData 數據量較大影響首屏加載性能。
3) 性能優化空間大:不會影響作頁面維度的性能優化(如首屏優先、請求前置)。
4) 包大小可控:組件是否複用能夠動態調配,好比把頁面中迭代較少的組件不復用以減小包大小。

劣勢

1) 提效有限:組件模式只能複用組件內的代碼,代碼複用率較低,頁面容器、邏輯層、網絡層小程序依然要本身維護一份代碼。
2) 複用組件維護成本高:組件的接口要考慮組件升級迭代的兼容性、可維護性問題,管理不當,容易產生質量隱患。
3) 接入成本較高:小程序須要實現 RN 的頁面邏輯,而後按照組件接口進行接入,有更高的接入成本。

兩組複用模式各有利弊,頁面模式複用率高,可是靈活性低、性能欠佳;組件模式輕便靈活,性能可控,能較好的處理平臺差別化問,可是複用率低、維護成本高。咱們在想有沒有一種方案能保留組件模式的靈活性,又能下降組件維護成本、提升複用程度。在業務實踐中,咱們探索出一套「組件+邏輯複用」的模式,能夠較好地解決上面提到的問題。

3.3.2 差別化下的邏輯複用

「組件+邏輯複用」模式依然保留組件複用的方式,可是在組件複用基礎上增長了邏輯層(包括頁面邏輯、網絡、數據層)的複用,這樣保留了組件靈活性,也增長了複用性。具體設計以下圖:

圖9 組件+邏輯複用模式原理圖

整個組件+邏輯複用模式設計圖如上,咱們按照圖片標註的序號進行一一解讀:

1) 邏輯複用接口實例:在小程序的頁面容器中,經過注入的方式獲取邏輯層複用的接口實例,經過這個實例即可以調用接口實現獲取、更改、監聽 Redux 的狀態,實質上就達到了邏輯複用的效果。
2) 頁面複用組件集:頁面能夠自由使用複用組件,複用組件可大可小,能夠雖然拼裝佈局,保留了組件模式良好的靈活性。
3) 小程序原生組件:頁面既可使用複用組件,也能夠用小程序原生組件來實現小程序差別化的功能和特性,這樣能較好的處理雙端差別性。小程序原生組件能夠經過 邏輯複用接口實例 來調用邏輯層功能,進而達到邏輯複用的效果。
4) 彈窗複用組件:彈窗複用組件和頁面複用組件同理,這邊主要說明能夠按照各種維度把複用組件分類,進而更好的作複用組件管理。
5) 複用組件庫:複用組件庫的複用組件可多可少,可大可小,若是頁面雙端差別性小,一個大組件便可知足。每一個複用組件集外層包一層 Reudx-Provider 並設置相同的 Store,即可以和邏輯層自動綁定上。由於 RN 組件自己就是基於 Redux 的,因此複用過程相對容易。
6) 業務邏輯層:最右側的業務邏輯層能夠簡單理解成3塊,一塊是基於 Redux Store 的數據層,這裏存放整個頁面模塊全部的數據和操做、監聽數據的接口,一塊是包含頁面內全部網絡請求的網絡層,另外就是用來流轉狀態和處理複用的 Reducer、Redux-Saga,以及配套的各類工具類。業務邏輯層能夠根據雙端的差別把 Reducer 與 Saga 分拆更小的單元實現差別化的邏輯複用,提高邏輯複用層的代碼可維護性。
7) 封裝複用接口:業務邏輯層包含整個頁面的業務邏輯,只要針對性開放接口給小程序,讓小程序可能獲取、更改、監聽 Redux 的狀態,那實質上就達到了邏輯複用的效果。開放接口給小程序有 2 種方式:邏輯 API 接口 和 Store。
8) 邏輯API接口:基於 Store 給小程序提供小程序真正須要的邏輯 API 接口,經過這些 API 小程序能夠來獲取數據來渲染 UI(如:渲染沒有複用的組件),也能夠更新數據,也能監聽複用組件內部的數據變化。
9) Store:把 Redux Store 暴露出去,小程序便利用 Store 實例能夠經過 getState、dispatch、subscribe來操做、監聽狀態機了,也就達到邏輯層複用的目的了。

這種方案的優點很明顯,它保留組件模式的靈活特性,能夠比較方便作差別化處理和性能優化。而邏輯複用層把 Redux 包含進來了,這樣不只轉化容易、不易出錯,並且邏輯複用接口基於 Redux 的 Store,接口較好設計,容易維護、不易出錯。而對於邏輯層,能夠根據業務上一些差別作 Reducer 與 Saga 分拆,把不須要複用的代碼邏輯排查在外,邏輯層複用也能夠作到像組件同樣熱插拔,按需引入,這樣也比較好作差別化代碼管理,挺高項目的可維護性,同時也能優先減小包大小風險。

3.4 跨端複用流程規範

爲在代碼跨端複用過程當中儘量提高開發效率並避免引入質量問題,咱們制定了差別化編碼規範、需求同步規範、複用組件規範等開發流程規範,如下將經過 RN 到小程序產品需求同步過程進行簡單的介紹。

圖10 跨端複用流程規範圖

1. 評估業務需求是否須要同步

針對 PM 提出須要同步的需求,客戶端儘可能將 RN 業務代碼複用至小程序,以提高開發效率。無需同步的需求將經過差別編碼規範進行控制,避免同步至小程序後增長潛在風險與測試成本。一般可以使用平臺判斷(如 iOS、Android、WX_Platform )的方式控制業務代碼是否打入複用組件包,也可經過 module.rn.js、module.wx.js 不一樣後綴文件方式完成相同接口不一樣邏輯的實現。

2. 評估是否有關聯依賴需求

如明確業務需求須要同步,先判斷該需求是否有前置需求依賴,再評估技術方案。如無依賴可直接開始複用適配工做;若有依賴,需判斷前置需求可否一塊兒同步或作適當降級,以此遞推,避免因前置依賴需求未同步出現不符合預期的問題。

3. 制定 RN 組件適配與小程序接入方案

明確需求同步範圍評估工做後,需完成如下技術評估工做:(1)明確需求是否須要新建複用組件仍是在原有的複用組件上進行迭代。如需新建複用組件 NPM 包,需根據組件複用規範進行技術選型,肯定使用「組件+邏輯複用模式」、「頁面模式」仍是「組件模式」,並制定相應的複用組件接口協議;(2)明確該需求是否須要開發 RN-小程序映射方法、組件,並評估相應的開發量。完成技術評估後需提早與小程序側溝通接入排期。

4. RN 組件適配開發

客戶端完成 RN 側需求開發後,即可進行復用組件適配小程序開發。完成適配開發工做後需在 RN 頁面與小程序 Demo 頁面中對複用組件同時進行測試,避免在適配小程序過程當中引入 RN 頁面 Bug。複用組件測試完畢後將 NPM 包以及相應的接口文檔提供給小程序接入,但在打包前需嚴格審查當前版本與上個版本間的 diff,避免不符合預期的代碼也被同步至小程序。

5. 小程序接入 RN 適配組件

適配完成後將組件打包提供給小程序側接入,接入後需在美團民宿小程序環境下再次進行自測。原則上客戶端同窗提供適配好的 RN 組件後,由小程序側同窗接入並測試,但咱們也鼓勵客戶端在完成 RN 組件開發與複用適配後,一併完成小程序側的組件接入工做,這樣需求開發完整度更高,並能有效減小跨端開發下的溝通成本。後續隨着大前端融合推動,RN-小程序代碼複用率將逐步提高,客戶端(iOS、Android)與 小程序代碼將傾向由一名同窗完成多端開發。

6. RN 適配代碼合入迭代分支

需求在小程序測試完畢後,將 RN 組件適配 Feature 分支代碼合入 Release 迭代分支,並在客戶端(iOS、Android)打包上線。

3.5 跨端複用質量保障

跨端複用場景下存在包括複用組件接口兼容性問題、組件間的依賴隱患問題、測試和監控的缺失問題,以及故障排查困難等各類質量隱患,咱們在業務實踐中,也探索出一系列解決這些隱患的質量保障措施,包括組件接口維護、組件依賴管理、雙重自測卡控、異常監控融合、雙端故障 SOP、跨端複用流程規範 。這些措施能有效保障複用場景下雙端的線上質量,民宿業務在跨端複用推動中,由於這些措施的保障護航,沒有出現任何的線上故障。

1. 組件接口維護

複用組件隨着業務迭代會不斷更新升級,組件升級過程當中便會帶來的組件接口、輸入、輸出的變更,進而產生兼容性隱患,好比組件輸入參數類型變更,而小程序端或RN端沒有及時兼容或者未知曉,很是容易引起線上質量問題。爲此,咱們制定了組件接口維護計劃,包括複用組件接口規範、組件版本管理規範、組件接口文檔建設等。複用組件接口規範要求複用組件接口、參數必須嚴格按照規範來,如參數類型使用基礎類型、只增少減原則、接口命名清晰、參數個數限制等等,減小雙端的接入組件難度,避免參數頻繁變更產生質量隱患。組件版本管理規範要求組件版本升級必須遵循語意化 2.0,而且有相應的版本升級文檔。組件接口文檔建設也是很重要的一環,每一個複用組件都有相應的文檔維護,記錄參數的增刪改查,接入方對組件接口變更一目瞭然,天然減小了接入風險。

2. 組件依賴管理

組件依賴主要存在兩個問題,第一,複用框架自己也在不斷升級優化、新的複用組件可能用新的編譯版本轉化而來而且依賴新的運行時渲染器,可是舊的複用組件可能會出現不兼容問題,所以咱們開發相關的工具,若是組件依賴的運行時渲染器版本和小程序內置的不一致就會發出警告,提示組件兼容性問題。第二,由於不一樣的複用組件來自不一樣的RN模塊,它們可能依賴不一樣版本的第三方庫,容易產生版本不一致的質量問題。目前的解決方案是把這些依賴庫分別打入各自的包裏,這樣複用組件間依賴相互獨立,互不影響。再結合 Tree-Sharking 的優化,打入的依賴的真實包大小並不大,用小量的包大小換取更穩健的質量保證。

3. 雙重自測卡控

在跨端複用場景下,一個複用模塊的改動要考慮雙端兼容和新舊版兼容問題,相比與以前有更高的出錯風險,更全面的自測能幫咱們儘早暴露問題,減小故障風險。因此咱們在 App 側和小程序側作了代碼自測覆蓋率卡控,要求改動代碼執行覆蓋率超過 90% 才能提測和上線。複用組件既在 RN 側自測過一遍,在小程序接入後又強制要求再自測一遍,雙重自測卡控更能保障組件質量和線上質量。

4. 異常監控融合

RN 和小程序側都有單獨的異常監控機制,包括 JS 異常監控、API 異常監控、自定義異常監控等。可是雙端的異常監控機制差異較大,在複用場景下二者交叉混用致使異常監控體系混亂,上報數據格式、策略、日誌不統一而形成監控體系誤告、漏告、排查困難、運維混亂等問題。因此咱們把雙端的異常監控模塊打通,適配了底層異常上報邏輯,統一了雙端的上報規範,告警策略、日誌、處理流程。異常監控體系雙端融合後,異常上報、監控、運維都順暢許多,也幫咱們發現很多的線上異常,是 RN-小程序跨端複用場景線上質量的堅固屏障。

5. 雙端故障SOP

鑑於雙端同窗存在技術上的隔閡和信息不對稱,當出現複用組件的故障或異常時,如何快速排查問題成爲一個痛點,小程序的錯誤日誌 RN 同窗不熟悉,小程序同窗不熟悉 RN 的業務代碼實現,框架層面的錯誤更難排查。爲此,咱們總體了梳理雙端故障 SOP,這裏麪包括常見日誌分析幫助鑑別是複用組件、小程序端、底層複用框架的問題和相應的解決方案,同時開發了 Source Map 錯誤反解工具協助RN同窗反解小程序日誌幫助快速排錯等等。這些 SOP 和工具可以在第一時間幫助雙端同窗自主或協助排查相關故障,快速止損。

6. 跨端複用流程規範

流程規範包括前面提到的複用組件規範、編碼規範、需求同步規範、分支管理規範等等也是質量保障的重要的一環,它讓研發流水線每一環都有嚴格的法律約束,保障整條研發流水線最終能把完整的產品交付到用戶手裏。

3.6 成果

RN-小程序跨端複用的設計方案在業務實踐中不斷完善,探索出效率相對最大化的複用模式。從開發效率角度來看,提高顯著。咱們總結了代碼複用率與人效提高率來評估效率的提高,兩個指標具體計算公式以下:

  • 代碼複用率:∑(RN 複用模塊代碼行數-模塊中 RN 與小程序平臺分支判斷代碼行數) / ∑(RN 代碼總行數+小程序原生代碼行數);其中,RN 複用模塊代碼行數是根據框架轉換生成的組件來肯定。
  • 人效提高率:∑(RN 開發耗時 + 小程序開發耗時 - (RN 開發耗時 + 轉換適配耗時)) / ∑(RN 開發耗時 + 小程序開發耗時);複用前須要RN與小程序側兩端的開發耗時,複用後只須要 RN 開發與複用組件轉換適配的耗時,根據複用先後的耗時能夠得出人效提高率公式。

根據轉換採用的模式不一樣,能夠得出代碼複用率與人效提高率,以下表所示:

轉換模式 代碼複用率 人效提高率
組件+邏輯複用模式 76% 42.36%
頁面複用模式 91% 46.71%

從表中能夠看出,頁面轉換模式複用了頁面與組件的代碼,代碼複用率能夠達到 90% 以上;組件複用模式複用了組件與部分業務邏輯代碼,複用率也能夠達到 76%。在人效提高方面,全部模式都能達到較高的人效提高率,代碼複用率越高人效提高率也越高,頁面轉換模式能夠複用頁面與數據狀態處理邏輯人效提高比組件轉換模式更高。

4. 總結

民宿大前端團隊爲解雙端研發效率之痛,傾力而尋跨端之技,淺嘗百草、深諳其理然後自建之,舉偏補弊、終解跨端框架性能之桎梏,青出藍而勝於藍。然後踐於實業,瑕弊昭然若揭。爲此,重設框架以謀其變(複用架構設計),尋之新式以盡其效(複用模式設計),立之新法以固其序(跨端複用流程規範),磨之利器以護其城(跨端複用質量保障),至此成果初成。然朝夕變化不休,路漫遠兮,吾當持之求索以適其變、順其道。跨端複用前行之鑑,故記以文,望有啓示,文畢。

做者簡介

凱林、森偉、熙辰、戈弋、少元等,均爲美團民宿前端團隊研發工程師。

招聘信息

美團民宿長期招聘 Android、iOS、FE 前端工程師,座標在福建廈門。感興趣的同窗可將簡歷發送至:tech@meituan.com(郵件主題請註明:美團民宿大前端)。

閱讀美團技術團隊更多技術文章合集

前端 | 算法 | 後端 | 數據 | 安全 | 運維 | iOS | Android | 測試

| 在公衆號菜單欄對話框回覆【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】等關鍵詞,可查看美團技術團隊歷年技術文章合集。

| 本文系美團技術團隊出品,著做權歸屬美團。歡迎出於分享和交流等非商業目的轉載或使用本文內容,敬請註明「內容轉載自美團技術團隊」。本文未經許可,不得進行商業性轉載或者使用。任何商用行爲,請發送郵件至tech@meituan.com申請受權。

相關文章
相關標籤/搜索