1. 程式人生 > 其它 >FW:美團民宿跨端複用框架設計與實踐

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

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

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

1. 背景

1.1 美團民宿業務介紹

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

1.2 美團民宿移動端現狀

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

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

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

儘管美團民宿 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. 跨端複用質量隱患:實現了複用便要考慮兩端的各種相容性問題,這就會產生各種質量上的隱患。如何在複用元件不斷迭代中,保障元件介面、輸入、輸出的相容性問題?如何保障各個複用元件底層依賴的統一、適配層介面的統一?雙端複用場景下,如何更好的做測試和監控?雙端同學存在各自技術認知的邊界,如何在出現問題時快速排查、及時止損?
  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. 總結

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

本文來自部落格園,作者:Slashout,轉載請註明原文連結:https://www.cnblogs.com/SlashOut/p/15429711.html 關注公眾號:數字化轉型