一文揭祕餓了麼跨端技術的演進、實踐與落地

本文會先帶領大家一起簡單回顧下跨端技術背景與演進歷程與在這一波兒接着一波兒的跨端浪潮中的餓了麼跨端現狀,以及在這個背景下,相較於業界基於 React/Vue 研發習慣出發的各種跨端方案,餓了麼爲什麼會選擇走另外一條路,這個過程中我們的一些思考、遇到及解決的問題和取得的一些成果,希望能給大家帶來一些跨端方面的新思路。

跨端技術背景與演進歷程

跨端,究竟跨的是哪些端?

自 90 年的萬維網出現,而後的三十多年,我們依次經歷了 PC 時代、移動時代,以及現在的萬物互聯(的 IoT )時代,繁榮的背後,是越來越多的設備、越來越多的系統以及各種各樣的解決方案。

總的來說,按照跨端的場景來劃分,主要包含以下 4 類:

而在當下,移動領域依然是絕對的主角,我們來看一下移動端的跨端技術都經歷了哪些階段。

移動跨端技術演進

隨着移動互聯網的蓬勃發展,端形態變的多樣,除了傳統的 Native、H5 之外,以動態化與小程序爲代表的新興模式百花齊放大行其道,世面上的框架 / 容器 / 工具也層出不窮,整個業態朝着碎片化方向發展。

對開發者來說,碎片化的直接影響,是帶來了包括但不限於,剛纔提到的設備平臺、操作系統、渲染容器、語法標準等方面的各種不確定性,增加了大量的學習、開發與維護成本。

於是,應運而生的各類跨端技術,核心在於從不確定性中找尋確定性,以保障研發體驗與產物一致性爲前提,爲各端適配到最優解,用最少成本達到最好效果,真正做到 "一次編寫,到處運行"。

移動跨端大致經歷瞭如下幾個階段:

回顧了以上跨端技術背景與演進歷程,在這股浪潮裏面,餓了麼的跨端投放情況是什麼樣的?投了哪些端?遇到了哪些問題?又是如何解決的?

餓了麼跨端投放訴求、現狀與策略

衆所周知,餓了麼是圍繞 O2O 爲用戶提供線上到線下服務的公司,通過對時、空、人、貨 的有機結合,來鏈接商家與消費者,相比於傳統電商,時空人貨本身具有區域屬性,這意味着我們做的不是一個大賣場生意,更多的是需要圍繞區域特性提供精細化的服務,這裏面有一系列時空、體驗、規模、成本的約束需要考慮與應對

而在這一系列約束背後,其實有一個各方共通的經營訴求:

這都導向一個目的:哪裏流量多,我們就需要在哪裏提供與消費者的連接能力。

那麼問題來了,流量在哪裏?現在的互聯網,更多都是在做用戶的時間與精力生意,背後拆解下來,其實有幾個關鍵因素可以衡量:用戶密度、用戶活躍度、市場佔有率與用戶時間分配,細化來看,其中任意幾個條件滿足,都可以作爲我們流量陣地的候選集。

餓了麼經過多年耕耘,對外部關鍵渠道做了大量佈局,業務陣地衆多,從效果上看,渠道業務無論是用戶流量規模還是訂單規模均對大盤貢獻度較高,且隨着業務的持續精進與外部合作環境的持續改善,增量渠道也在不斷的湧現中。

在這麼多的業務陣地中,投放在各個端的應用的形態基於:

等的差異和限制,目前形成了 以小程序爲主,H5 爲輔 的承接方式,而這些差異帶來了大量的不確定性,主要體現在:

而我們要做的,就是在這兩種不確定性中,找到技術能帶來的確定性的事情。如何系統性的解決這些問題,則成爲我們在保障渠道業務靈活性的基礎上持續提升研發效率和體驗的關鍵。

在差異應對上,業務研發最理想的方式是對底層的變化與不一致無感,安心應對業務訴求,基於這個點出發,我們的主要策略是:圍繞 “研發體驗一致性提升與複雜應用協作機制改進”來保障業務高效迭代。這需要一套強有力的、貼合業務特性的基礎設施來支撐。首先想到的便是如何通過 “推動框架統一” 和“實現一碼多端”,來爲業務研發降本增效,然而理想很豐滿,現實很骨感:

框架的升級通常情況下,大概率會帶來業務重構,綜合評估之後,作爲外部渠道流量大頭的小程序業務,則成爲了我們優先要保障的業務,也基於此,爲了儘可能降低對業務的影響和接入成本,我們明確了以小程序爲第一視角來實現多端。

基於小程序跨端的行業現狀和思考

在明確了方向之後,那麼問題來了:業界有沒有適合我們的開源的框架或解決方案呢?

業界有哪些面向於小程序的研發框架?

市面上,從小程序視角出發,具備類似能力的優秀多端框架有很多,有代表性的如 Taro、uni-app、Rax 等,大多以 React 或者 Vue 作爲 DSL

那麼這些框架能否解決我們所面臨的問題?答案是:並不能。

爲什麼餓了麼選擇以小程序 DSL 爲基礎實現跨端?

綜合 餓了麼 的渠道業務背景需要考慮以下幾點:

在做了較多的橫向對比與權衡之後,上面的這些框架對於我們而言採納成本過高,所以我們選擇了另外一條相對艱辛但更爲契合餓了麼多端演進方向的路:以小程序原生 DSL 爲基礎建設跨端解決方案,最大限度保障各端產物代碼貼合小程序原生語法,以此儘可能降低因同構帶來的體驗損耗和業務多端接入成本。

基於小程序 DSL 的跨端解決方案

確定以小程序 DSL 作爲方向建設跨端解決方案之後,首先要解決的就是如果將已有的小程序快速適配到多端。這就需要對各個端的差異做細緻的分析並給出解決方案。

如何解決小程序多端編譯?

爲了能夠兼顧性能和研發體驗,我們選擇了 編譯時(重)+ 運行時(輕) 的解決方案。

靜態編譯解決了哪些問題?

靜態編譯轉換主要用於處理 JS、WXS/SJS、WXML/AXML、WXSS/ACSS、JSON 等源碼中約束強且不能動態修改的部分,如:

等,原理是通過將源碼文件轉換爲 AST(抽象語法樹),並通過操作 AST 的方式來實現將源碼轉換爲目標平臺的代碼。

但靜態編譯只能解決一部分的差異,還有一些差異需要通過運行時來抹平。

運行時補償解決了哪些問題?

運行時補償主要用於處理靜態編譯無法處理或者處理成本較高的一些運行時動態內容,如:

等等,類似的場景有很多,這裏不再一一列舉。

通過靜態編譯 + 運行時補償的方式,我們便可以讓現有的微信或支付寶小程序快速的遷移到其他小程序平臺。

如何解決小程序轉 Web?

伴隨外賣小程序上線多年之後,各個大的渠道(支付寶、手淘、微信等)已切流爲小程序承載,但是還有很多細分渠道或非小程序環境渠道,比如:各個銀行金融渠道,客戶端的極小包等,還需要依賴 H5 的形態快速投放,但當前餓了麼的業務越來越複雜,相關渠道的投入資源有限,歷史包袱重、迭代成本大等原因,產品功能和服務能力遠遠落後於小程序和餓了麼 App。而業務急需一個可以將小程序的功能快速複製到 h5 端的技術方案,以較低的研發和維護成本,滿足業務多渠道能力對齊上線的訴求。

基於這個背景,我們自然而然的可以想到,即然小程序可以轉其他小程序,那麼是否也可以直接將小程序直接轉換爲 Web,從而最大程度上提升人效和功能對齊效率。

具體是怎麼實現的?主要手段還是通過編譯時 + 運行時的有機結合:

Web 轉端編譯原理

編譯部分和小程序轉小程序的主要區別和難點是:需要將 JS、WXS/SJS、WXML/AXML 等文件統一轉換併合併爲 JS 文件並將 WXML/AXML 文件轉換爲 JSX 語法,將樣式文件統一轉換爲 CSS 文件,並將小程序的頁面和組件都轉換爲 React 組件。

運行時原理

轉 Web 的運行時相較於轉換爲其他小程序會重很多,爲了兼顧性能和體驗,運行時的核心在於提供與小程序對等的高效運行環境,這裏麪包含四個主要模塊:

基於這四個模塊,配合編譯時的自動注入和代碼轉換,以及路由映射等,我們就可以把一個小程序轉換爲一個 Web 的 SPA(單頁) 或者 MPA(多頁) 應用,也成功的解決了業務的研發效率問題,目前 餓了麼的新 M 站就是基於這套方案在運行。

如何解決多端多形態問題?

解決了各端的編譯轉換問題,是不是就萬事大吉,業務接下來只要按部就班的基於這套能力實現一碼多端就可以了?

然而並不是,隨着餓了麼的業務場景和範圍快速拓展,誕生了一些新的訴求,比如:

等等,大家如果仔細觀察這些訴求,就會發現一個共同的點:就是小程序的形態不一樣。

雖然我們已經具備了多端的能力,但是形態的差異沒有解決掉,而之前相關業務的做法是,儘可能將通用功能沉澱到組件庫,並按照多端的方式分端輸出產物,然而由於相同業務在不同小程序端形態差異性的問題,業務上難以自行規避,而重構的成本又比較高,所以有一部分業務選擇了直接按照不同的端不同的形態(如微信、支付寶、淘寶、抖音)各自維護一套代碼,但這樣做不僅功能同步迭代週期被拉長,而且 BUG 較多,維護困難,研發過程也是異常痛苦。

小程序形態差異有哪些?

形態差異是指 小程序、小程序分包、小程序插件 三種不同形態的運行方式差異以及轉換爲其他形態之後產生的差異,具體如下:

等等,相關形態差異可結合各個小程序平臺查看,這裏僅羅列常見的部分。

如何解決這些差異?

這裏舉幾個例子:

通過在編譯過程中,自動向產物中注入對 App 和 getApp 的運行時模擬實現,這樣就可以解決分包和插件下方法缺失或者是衝突引起的報錯問題。

方法也是類似,可以在編譯的過程中檢測全局樣式是否存在,如果存在,則將對應的全局樣式引用自動注入到每一個頁面和組件中來解決全局樣式失效的問題。

而針對各個小程序平臺的 NPM 使用規則不同的問題,可以通過依賴解析、動態分組、組件提取打包、引用替換等方式,將 NPM 抽取到特定的地方,並將對應的組件和頁面中的引用進行替換,來解決 NPM 的支持問題,這樣業務就可以基本無腦使用各類 NPM 而不用關心平臺差異。

以此類推,將業務難以自行適配的差異,逐一解決之後,剩餘的一些功能差異,則由業務基於條件編譯的方式來自行適配,這樣便可以大大的降低業務形態轉換成本,同時也形成了我們面向多端場景下的形態轉換方案。

那麼到這裏,多端轉換的問題纔算是基本解決了。

如何治理 “複雜小程序”?

如果說上面講的內容都是聚焦在如何通過編譯的方式來解決多端同構以及形態問題的話,那麼接下來要解決的就是針對 “複雜小程序” 的應用架構與研發協作的問題了。

首先介紹下我們所定義的 “複雜小程序”,即具備跨業務領域的、長週期的、多團隊協同的、呈現主鏈路 + 多分支業務模式的應用,其之所以 “複雜”,主要體現在應用形態多樣、訴求多樣、關聯業務面廣等特性上。

對於餓了麼來說,每個渠道陣地均相當於一個小型餓了麼 APP,除了在研發上提供便利外,還需一套可靠的應用架構來保證其有序演進。

同時,由於渠道之間定位不同,各域的業務、產品及研發對各渠道重視程度與投入比重均有差異,間接導致渠道間相同業務能力的參差不齊,且不同渠道功能缺失的情況持續出現。

我們以餓了麼微信小程序爲例:

面臨的問題有哪些?

解決方案:線下線上結合的集成研發模式

針對上面兩個 “複雜小程序” 所面臨的核心問題,我們針對性的通過 「線下集成研發」和「線上研發協作」來解決。

線下集成研發

重點考慮的是提供什麼樣的集成研發能力,允許以業務單元維度將多個獨立的構建(宿主、小程序、插件、分包等)組成一個可用的小程序,消除業務之間強依賴關係,從而達成業務可獨立開發、調試和部署的目的,方面統一業務協作流程、降低多端同構成本,關鍵策略:

將小程序宿主和各個業務模塊(分包、小程序、插件)通過形態轉換、拉包、編譯、構建、合併等一系列處理後,合併爲一個完整小程序,且根據不同的場景可以支持:

這樣我們就可以解決線下研發的問題。

線上研發協作

前面介紹的 “線下集成研發” 爲業務單元提供了無阻塞的開發與調試能力,但對於餓了麼業務整體演進來說,重視的是每個版本功能的可用與可控,這裏面除了將集成的範圍擴展到所有業務域的之外,還需要標準化的流程約束:

具體方式上,在機制層面提供了業務類型定義的能力,開發者可將工程做對應標記(主包、分包、插件、獨立小程序),在流程層面定義了開發、集成與發佈三個階段,這和 APP 的研發流程有些類似:

再進一步,多端業務的最佳實踐

通過線下集成 + 線上協作的雙重能力加持,結合已有的多端編譯能力,在成功的支撐了餓了麼多端渠道業務的穩定高效研發的同時,我們也在思考,面向於未來的多端研發模式應該是個什麼樣子?

下圖是我們期望同時也是餓了麼目前多端應用架構正在演進中的樣子:

從圖上可以看出,我們將應用架構劃分爲三層(從下往上看):

基於這種分層協作模式,可以最大程度上消除業務對多端差異的感知,可以將重心放在如何更好的爲用戶提供服務上。

以上內容爲餓了麼基於小程序 DSL 的跨端實踐和解決方案,下面我們來看一下具體取得的成果。

跨端成果

餓了麼各渠道業務效果展示

業務一碼多端研發提效數據

能力沉澱 — 餓了麼自研 MorJS 多端研發框架

MorJS 開源

我們將餓了麼在跨端多渠道上的多年沉澱和解決方案,融合爲 MorJS 多端研發框架,並通過 Github 開源的方式向社區開放。

GitHub 倉庫地址:https://github.com/eleme/morjs

下圖爲 MorJS 的完整架構圖:

MorJS 框架目前支持 :

並支撐了餓了麼 C 端大多數業務在各個渠道上的研發和投放。

MorJS 爲餓了麼解決了大量業務在多端研發上的差異問題,讓小程序開發的重心回到產品業務本身,減少使用者對多端差異兼容的投入。通過 MorJS 的開源,我們期望能把其中的實現細節、架構設計和技術思考呈現給大家,爲更多有類似多端同構需求的企業和開發者服務。同時,我們也希望能夠藉此吸引到更多志趣相投的小夥伴參與共建,一起加速小程序一碼多端能力的發展。歡迎廣大小程序開發者們與我們交流。

MorJS 特性介紹

爲了能夠幫助社區的用戶可以快速上手,我們在易用性、標準化和靈活性方面做了大量的準備:

同時也提供了豐富的文檔:https://mor.eleme.io/ 供大家查閱。

用戶原聲

MorJS 上線的這幾個月裏面,我們收到了一些社區用戶的正向反饋,也收到了一些訴求和問題,其中用戶最擔心的問題是:MorJS 是不是 KPI 項目,是否會長期維護?

這裏借用一下我在 Github 項目的討論區(Discussions)的回覆:

如果大家對 MorJS 感興趣,期望有更多瞭解或者在使用 MorJS 中有遇到任何問題,歡迎在後臺回覆【MorJS】加入社區服務羣反饋、交流和學習。

展望未來

未來,在現有的 MorJS 的能力基礎上,我們會進一步完善已有的多端能力,提升多端轉換可用度,完善對各類社區組件庫的兼容,並持續擴展編譯目標平臺的支持(如 鴻蒙、快應用等),在持續爲餓了麼自身業務和社區用戶提供高質量服務的同時,期望有朝一日 MorJS 可以成爲業界小程序多端研發的基礎設施之一。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/h8HDtYLj0skRsPSkmEtShg