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

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

跨端技術背景與演進歷程

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

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

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

  • 跨設備平臺,如 PC(電腦)/ Mobile(手機)/ OTT(機頂盒)/ IoT(物聯網設備)。不同的設備平臺往往意味着不同的硬件能力、傳感器、屏幕尺寸與交互方式
  • 跨操作系統,如 Android/iOS/HarmonyOS。不同的操作系統爲應用開發通常提供了不同的編程語言、應用框架和 API
  • 跨移動應用,如 微信/支付寶/手淘/抖音/快手等。由於移動平臺 CS 架構 及 App 間天然的壁壘,不同 App 間相互隔離,並各自在其封閉體系內遵循一套自有標準進行各類資源的索引、定位及渲染。而同一業務投放至不同 App 端時,就需要分別適配這些不同的規則。
  • 跨渲染容器,如 Webview/React Native/Flutter。前面三類場景催生了針對不同設備平臺、不同操作系統、不同 App 間解決方案,因而移動領域的各種 Native 化渲染、自繪渲染與魔改 Webview 的方案也由此被設計出來,在嘗試解決跨端問題的同時,也一定程度上提高了跨端的遷移門檻和方案選擇難度。

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

移動跨端技術演進

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

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

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

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

  • H5 Wap 階段:Web 天然跨平臺,響應式佈局是當時的一個主要手段,但由於早期網絡環境原因,頁面加載速度無法滿足業務預期,加之設備傳感器標準缺失、內存佔用大、GPU 利用率低等問題,在移動設備量爆發伊始,難堪大任的論調一下子被推上風口浪尖,並在 12 年達到頂峯。
  • Hybrid 階段:典型代表是 Cordova/ionic。功能上看,Hybrid 解決了歷史兩大痛點:
    • 1)性能,依靠容器能力,各類離線化、預裝包、Prefetch 方案大幅減少加載耗時,配合編碼優化在 3/4G 時代使 H5 的體驗上了一個臺階;
    • 2)功能,通過 JSBridge 方式規避了與 Native 原生割裂帶來的底層能力缺失。
  • 框架+原生階段:典型代表是 ReactNative/Weex。基於 JSC 或類似的引擎,在語法層與 React/Vue 結合,渲染層使用原生組件繪製,嘗試在研發效率與性能體驗間尋找更佳的平衡點,各類領域解決方案(受限 DSL + 魔改 web 標準 + Native 渲染能力)開始湧現,拉開了大前端融合渲染方案的序幕。
  • 自繪渲染階段:典型代表是 Flutter/Qt。這裏的 “自繪” 更強調不使用系統原生控件或 Webview 的渲染管線,而是依賴 Skia、Cairo 等跨平臺圖形庫,自底向上自建渲染引擎、研發框架及基礎配套的方式,其跨 Android/iOS 的特性迅速點燃了客戶端研發領域。
  • 小程序階段:典型代表是 微信/支付寶小程序。小程序是被創造出來的,其本質是各 APP 廠商出於商業考量構造了相對封閉的生態,在標準與能力上無論與 Web 還是廠商之間均存在差異,能力上是自定義 DSL & API + Hybrid + 同層渲染 + 商業管控的綜合體。市面跨端方案策略均是錨定一種研發規約進行各形態編譯時與運行時的差異抹平與適配。

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

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

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

  • 對於商家來說:爲了有更好的經營需要有更多曝光,與客戶有更多的觸達,以便帶來成交。
  • 對於平臺來說:爲了能夠讓更多消費者享受我們的服務,除了深耕自己的超級APP(餓了麼APP)外,還需要在人流量大的地方加大曝光、聲量與服務能力來擴大我們的規模。

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

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

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

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

  • 渠道的運行環境
  • 渠道的流量特性
  • 渠道的業務定位
  • 渠道的管控規則

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

  • 渠道環境的高度不確定性:對接了這麼多渠道,每個端的運行環境存在巨大差異,拿小程序能力舉例,即使是個別 APP 的小程序方案借鑑了微信的思路,由於其內部商業能力、產品設計思路、能力成熟度與完整度、研發配套(語法、框架、工具等)的不一致也會使研發體感有明顯的不同,這對技術同學來說,帶來的是渠道環境的高度不確定性;
  • 業務訴求的高度不確定性:同時,我們所投放的 APP 都可劃分到某些細分領域,用戶特性與用戶在該平臺上的訴求不一,渠道定位也不一致,隨着每個業務域的功能演進越來越多,多個渠道功能是否對齊、要不要對齊、有沒有對齊、什麼時候對齊成了一個非常現實和麻煩的事情,同時業務域之間可能還存在功能上的關聯,這進一步提高了其複雜度,在沒有一個好的機制與能力保障下,業務、產品、研發對每個渠道的同步策略、能力範圍的感知會有較大偏差,甚至於一個需求的迭代,每個端什麼時候能同步都變成了一個無法預期的事情,這對於業、產、研來說,帶來的是業務訴求上的高度不確定性。

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

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

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

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

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

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

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

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

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

  • 改造成本:以支付寶、微信、淘寶爲代表的餓了麼小程序運營多年,大部分存量業務是以支付寶或微信小程序 DSL 來編寫,需關注已有業務邏輯(或組件庫)的改造成本,而採納業界框架基本上會直接引發業務的大量重構,這個改造成本是難以接受的。
  • 性能體驗:渠道業務是餓了麼非常重要的流量陣地,重視程度與APP無差,在體驗和性能上有極致的要求,所以我們期望在推動跨端的同時,儘可能減少運行時引入帶來的性能損耗。
  • 業務協同:由於每個渠道都基本相當於一個小型的餓了麼APP,複雜度高,涉及到多業務域的協同,包括主線步調一致性考量、多業務線/應用類型集成、全鏈路功能無縫銜接等,在此之外還需給各業務線最大限度的自控與閉環能力,背後需要的是大型小程序業務的一體化研發支撐。

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

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

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

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

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

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

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

  • 模塊引用:JS/WXS/SJS/WXML/AXML/WXSS/ACSS/JSON 等源碼中的模塊引用替換和後綴名修改;
  • 模版屬性映射或語法兼容:AXML/WXML 中如 a:if → wx:if、 onTap → bind:tap、{ {`${name}Props`}} → { {name + 'Props'}} 等;
  • 配置映射:如頁面 { "titleBarColor": "#000000" } → { "navigationBarBackgroundColor: "#000000", "navigationBarTextStyle": "white" }

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

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

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

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

  • JSAPI:實際業務使用上,不管是 JSAPI 的名字還是 JSAPI 的入參都會存在動態賦值的情況,導致了在 JSAPI 的真實調用上,很難通過 AST 去解析出實際傳參;
  • 自定義組件 - Props 屬性:比如,支付寶屬性使用 props 聲明,而微信屬性使用 properties 聲明,配置方式不同且使用時分別使用 this.props.x及 this.properties.x的方式獲取,同時可能存在動態取值的情況;
  • 自定義組件 - 生命週期:支付寶小程序中的didUpdate生命週期,在觸發了props和data更新後都會進入didUpdate這個生命週期,且能夠在didUpdate中訪問到prevProps / prevData,而在微信小程序中靜態轉義出這個生命週期就意味着你需要去動態分析出didUpdate裏面要用到的所有屬性,然後去動態生成出這些屬性的監聽函數。這顯然可靠程度是極其低的;

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

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

如何解決小程序轉 Web?

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

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

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

Web 轉端編譯原理

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

運行時原理

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

  • 框架:提供了小程序在 Web 中的基礎運行時功能,比如:Page 、Component 、App 等全局函數,並且提供完整的生命週期實現,事件的註冊、分發等
  • 組件:提供小程序公共組件的支持,比如 view、button、scroll-view 等小程序原生提供的組件
  • API:提供了類似小程序中 wx 或者 my 的 一系列 api 的實現
  • 路由:提供了頁面路由支持和 getCurrentPages 等方法支持

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

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

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

  • 支付寶的獨立小程序作爲分包接入微信小程序
  • 淘寶 / 支付寶的小程序插件作爲分包接入某個現有的微信小程序
  • 支付寶的獨立小程序作爲插件接入淘寶小程序插件
  • 支付寶小程序插件作爲分包接入微信或抖音小程序

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

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

小程序形態差異有哪些?

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

  • getApp 差異
    • 小程序: 可通過 getApp() 來獲取全局 App 實例及實例上掛載的屬性或方法
    • 小程序插件: 無法調用 getApp()
    • 小程序分包: 可通過 getApp() 來獲取全局 App 實例及實例上掛載的屬性或方法;但當通過小程序轉換爲分包後,分包自身原本調用的 getApp 將失效,並被替換爲宿主小程序的 getApp
  • App 應用生命週期 差異
    • 小程序: 應用會執行 onLaunch、onShow、onHide 等生命週期
    • 小程序插件: 無應用生命週期
    • 小程序分包: 無應用生命週期
  • 全局樣式(如:app.wxss 或 app.acss)差異
    • 小程序: 可通過全局樣式來聲明全局樣式
    • 小程序插件: 無全局樣式
    • 小程序分包: 無全局樣式
  • NPM 使用限制
    • 小程序: 各個小程序平臺支持和限制情況不一
    • 小程序插件: 各個小程序平臺支持和限制情況不一
    • 小程序分包: 各個小程序平臺支持和限制情況不一
  • 接口調用限制
    • 小程序: 無限制
    • 小程序插件: 存在大量的接口調用限制,如 開發支付寶小程序插件 或 開發微信小程序插件
    • 小程序分包: 無限制
  • 路由差異
    • 小程序: 轉換到其他形態後自身路由會發生變化
    • 小程序插件: 轉換到其他形態後自身路由會發生變化,跳轉插件頁面需要包含 plugin:// 或 dynamic-plugin:// 等前綴,小程序或分包則不需要
    • 小程序分包: 轉換到其他形態後自身路由會發生變化
  • getCurrentPages 差異
    • 小程序: 無限制
    • 小程序插件: 無法通過 getCurrentPages 獲取到小程序的頁面堆棧
    • 小程序分包: 無限制
  • 頁面或組件樣式差異
    • 小程序: 無限制
    • 小程序插件: 基本選擇器只支持 ID 與 class 選擇器,不支持標籤、屬性、通配符選擇器
    • 小程序分包: 無限制

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

如何解決這些差異?

這裏舉幾個例子:

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

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

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

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

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

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

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

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

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

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

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

面臨的問題有哪些?

  • 工程複雜導致研發效率低:大量的團隊在一個單體小程序應用上研發,帶來的直接問題就是小程序巨大化帶來的研發體驗差和編譯效率低,且業務相互依賴,單一模塊構建失敗會引發整個項目的失敗,比如餓了麼微信小程序單次編譯的時間超過了半個小時,且體積逼近 20m 上限。
  • 研發流程不規範導致穩定性差:同時由於不同的業務團隊迭代週期不一致,而每次發版都需要所有業務的代碼一起發,哪怕是某個業務分包或者插件沒有更新,但是對應的底層依賴庫發生了變更,也極有可能引入線上 BUG,導致測試迴歸的成本居高不下,發版質量難以保障。

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

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

線下集成研發

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

  • 提供統一的集成研發方式和流程
  • 提供標準、可複用的集成產物規範
  • 爲複雜小程序提供解耦工具和集成方法
  • 標準化小程序宿主、小程序插件、小程序分包、小程序模塊之間的通信及能力注入方式

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

  • 主子分包研發模式:基於不同業務對小程序中的分包進行拆分,以達到各個業務相互解耦,獨立迭代的目的;
  • SDK 研發模式:將通用的頁面或組件封裝置某個 NPM 包中作爲提供特定功能的 SDK 交由業務使用;
  • 小程序插件研發模式:集成研發也可以用支持標準的小程序插件研發。

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

線上研發協作

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

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

  • 開發:各業務應用自行研發並結合平臺部署測試,開發測試通過,等待窗口期開啓進入集成測試;
  • 集成:管理員設置集成窗口期,在窗口期,允許業務多次集成研發,確認最終要進集成的穩定版本,期間主包管理員可多次部署體驗版用於集成測試。窗口期結束後,不允許隨意變更;
  • 發佈:集成測試通過,各業務進行代碼 CR 並進入發佈階段,等候主包提審通過發佈上線,最終由管理員完成本次迭代發佈,發佈完成後,符合標準的主分包產物會被保存下來,後續的迭代中,如果某個分包未發生變更,則會直接複用產物,極大的降低了業務的發佈風險,並提升了整體的構建效率。

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

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

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

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

  • 基礎服務與研發規範:最底部的是基礎服務與研發規範,由 多端研發框架、多端研發平臺和多端研發規範,來提供統一的研發支撐,保障業務研發的基礎能力、體驗和效率,並負責將相關的業務統一打包、封裝、集成,並部署和投放到不同的渠道;
  • 宿主應用框架:第二層是宿主應用框架(Framework),也可以認爲是多端統一解決方案,承接了面向於業務研發並適配了多端差異的基礎 API(如 登錄、定位、請求、路由、實驗、風控、埋點、容器等)、基礎組件和最佳實踐,通過分渠道的配置化運行、標準化的接入手段和中心化的能力管理,來保障整體框架的輕量化、標準化與持續迭代和升級;
  • 渠道應用主體:最上層是各個業務的應用實體,有一個殼工程 + N個業務工程組成,殼工程承接各個渠道定製化的一些能力,而並將下層應用框架的能力暴露給上層的各個業務,各個業務只需要關心兩件事即可:
    • 多端形態:以什麼樣的形態接入到對應的渠道(即殼工程中)?
    • 業務功能:不同的渠道需要展示哪些功能?

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

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

跨端成果

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

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

  • 研發提效:採用一碼多端和集成研發模式的業務平均提效 70%,同構的端越多提效越多
  • 多端佔比:餓了麼內部 85%+ 的多端業務在基於這套方案實現多渠道業務研發和投放
  • 業務覆蓋:涵蓋了餓了麼全域的各個業務板塊

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

MorJS 開源

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

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

下圖爲 MorJS 的完整架構圖:

MorJS 框架目前支持 :

  • 2 種 DSL:微信小程序 DSL 或 支付寶小程序 DSL
  • 4 種編譯形態:小程序、小程序插件、小程序分包、小程序多端組件
  • 9 個目標平臺:微信、支付寶、百度、字節、快手、釘釘、手淘、QQ、Web

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

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

MorJS 特性介紹

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

易用性:

  • DSL 支持:可使用微信小程序 DSL 或 支付寶小程序 DSL 編寫小程序,無額外使用成本;
  • 多端支持:支持將一套小程序轉換爲各類小程序平臺及 Web 應用, 節省雙倍人力;
  • 快速接入:僅需引入兩個包,增加一個配置文件,即可簡單快速接入到現有小程序項目;

標準化:

  • 開箱即用:內置了腳手架、構建、分析、多端編譯等完整研發能力,僅需一個依賴即可上手開發;
  • 表現一致:通過編譯時+運行時抹平多端差異性,讓不同平臺的小程序獲得一致的用戶體驗;
  • 形態轉換:支持同一個項目的不同的形態,允許小程序、分包、插件不同形態之間的相互轉換;

靈活性:

  • 方便擴展:MorJS 將完備的生命週期和內部功能插件化,使用插件(集)以滿足功能和垂直域的分層需求;
  • 類型支持:除小程序標準文件類型外,還支持 ts、less/scss、jsonc/json5 等多種文件類型;
  • 按需適配:可根據需求選擇性接入適配能力,小項目僅需編譯功能,中等項目可結合編譯和頁面注入能力,大型項目推薦使用複雜小程序集成能力;

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

用戶原聲

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

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

展望未來

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

作者|羽境

點擊立即免費試用雲產品 開啓雲上實踐之旅!

原文鏈接

本文爲阿里雲原創內容,未經允許不得轉載。

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