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

跨端技術背景與演進歷程

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

自 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 可以成為業界小程序多端研發的基礎設施之一。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/34964.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/34964.shtml
英文地址,請注明出處:http://en.pswp.cn/news/34964.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Apollo】Apollo-ros版本架構學習與源碼分析

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 這篇文章主要介紹Apollo-ros版本架構學習與源碼分析。 無專精則不能成,無涉獵則不能通。——梁啟超 歡迎來到我的博客,一起學習,共同進步。 喜歡的朋友可以關注一下&a…

微信小程序如何自定義分享卡片文案和圖片

微信小程序提供了onShareAppMessage方法,專門用來監聽用戶點擊頁面內轉發按鈕(button 組件 open-type"share")或右上角菜單“轉發”按鈕的行為,并自定義轉發內容。 > 注意:只有定義了此事件處理函數&…

Android studio 設置安卓手機

參考這個鏈接 ghttps://developer.android.com/studio/debug/dev-options 列出常用手機的設置,但是我的手機不在此列 Google Pixel Settings > About phone > Build number Samsung Galaxy S8 and later Settings > About phone > Software informa…

git: ‘lfs‘ is not a git command. see ‘git --help‘

在克隆hugging face里面的項目文件的時候,需要用到git lfs,本文介紹安裝git lfs方法 在Ubuntu下 curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash sudo apt-get install git-lfs在Windows下 到這個鏈…

解決GitHub的速度很慢的幾種方式

1. GitHub 鏡像訪問 這里提供兩個最常用的鏡像地址: https://hub.njuu.cf/search https://www.gitclone.com/gogs/search/clonesearch 也就是說上面的鏡像就是一個克隆版的 GitHub,你可以訪問上面的鏡像網站,網站的內容跟 GitHub 是完整同步…

期權定價模型系列【4】—期權組合的Delta-Gamma-Vega中性

期權組合的Delta-Gamma-Vega中性 期權組合構建時往往會進行delta中性對沖,在進行中性對沖后,期權組合的delta敞口為0,此時期權組合仍然存在gamma與vega敞口。因此研究期權組合的delta-gamma-vega敞口中性是有必要的。 本文旨在對delta-gamma-…

關于新手學習STM32開發應該如何入門?

對于新手來說,學習STM32開發可能會感到困惑,尤其是在拿到開發板后該如何入門。在這里有嵌入式學習路線,畢設,各種項目,需要留個6。以下是部分內容概述:硬件介紹:了解STM32開發板的基本硬件組成和…

Springboot 默認路徑說明

Spring Boot基本上是Spring框架的擴展,它消除了設置Spring應用程序所需的樣板配置,極大的方便了開發者,其默認識別路徑如下: Spring Boot 作為Spring默認將 /** 所有訪問映射到以下目錄: 1、classpath:/static 用于加…

【密碼學】穴居人密碼

穴居人密碼 文字記載中,有時會把來自古希臘文化之前的各種記錄作為密碼學的例子,但稱它們為密碼學一定太不嚴格了,這是因為那些方法都太原始了。密碼學的起源能追溯到多早,取決于你把密碼學的相關定義確定得有多寬泛。大多數作者都…

每日后端面試5題 第四天

1. 線程池的核心參數(高薪常問) (1)corePoolSize:核心線程個數 (2)maximumPoolSize:最大線程個數 (3)keepAliveTime:最大存活時間 &#xff0…

如何在Vue中進行單元測試?什么是Vue的模塊化開發?

1、如何在Vue中進行單元測試? 在Vue中進行單元測試可以提高代碼的可維護性和可讀性,同時也能夠幫助開發者更快地找到代碼中的問題和潛在的錯誤。下面是一些在Vue中進行單元測試的步驟: 安裝單元測試工具 首先需要安裝一個單元測試工具&…

第8章 【C語言】善于利用指針

8.1 指針是什么 由于通過地址能找到所需的變量單元,可以說,地址指向該變量單元。將地址形象化稱為“指針”。 直接按變量名進行的訪問,稱為“直接訪問”方式。 還可以采用另一種稱為“間接訪問”的方式,即將變量i的地址存放在另…

如何讓你的圖片服務也有類似OSS的圖片處理功能

原文鏈接 前言 有自己機房的公司一般都有一套存儲系統用于存儲公司的圖片、視頻、音頻、文件等數據,常見的存儲系統有以NAS、FASTDFS為代表的傳統文件存儲,和以Minio為代表的對象存儲系統,隨著云服務的興起很多公司逐漸將數據遷移到以阿里云…

二叉樹的性質和完全二叉樹的性質

二叉樹的性質: 在二叉樹的第i層至多有 2 i 1 ( i > 1 ) 2^{i1}(i>1) 2i1(i>1) 深度為k的二叉樹最多有 2 k ? 1 2^k-1 2k?1個結點 對于任意一棵二叉樹T,如果其終端結點數為 n 0 n_0 n0?,度為2的結點數為 n 2 n_2 n2?,則 n 0 …

【劍指 Offer 39】數組中超過一半的數字

題目: 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。 你可以假設數組是非空的,并且給定的數組總是存在多數元素。 示例: 輸入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 輸出: 2 思考: 方法一:投…

5.0 Python 定義并使用函數

函數是python程序中的基本模塊化單位,它是一段可重用的代碼,可以被多次調用執行。函數接受一些輸入參數,并且在執行時可能會產生一些輸出結果。函數定義了一個功能的封裝,使得代碼能夠模塊化和組織結構化,更容易理解和…

企業有VR全景拍攝的需求嗎?能帶來哪些好處?

在傳統圖文和平面視頻逐漸疲軟的當下,企業商家如何做才能讓遠在千里之外的客戶更深入、更直接的詳細了解企業品牌和實力呢?千篇一律的紙質材料已經過時了,即使制作的再精美,大家也會審美疲勞;但是你讓客戶遠隔千里&…

(MySQL經驗)之MySQL單表行數最好低于2000w

作為在后端開發,是不是經常聽到過,mysql 單表最好不要超過 2000w,單表超過 2000w 就要考慮數據遷移了,表數據都要到 2000w ,查詢速度變得賊慢。 1、建表操作 建一張表 CREATE TABLE person( id int NOT NULL AUTO_INCREMENT PRI…

如何讓ES低成本、高性能?滴滴落地ZSTD壓縮算法的實踐分享

前文分別介紹了滴滴自研的ES強一致性多活是如何實現的、以及如何提升ES的性能潛力。由于滴滴ES日志場景每天寫入量在5PB-10PB量級,寫入壓力和業務成本壓力大,為了提升ES的寫入性能,我們讓ES支持ZSTD壓縮算法,本篇文章詳細展開滴滴…

Python 監控 Windows 服務

Python 監控 Windows 服務 Python 在 Windows 系統上可以使用 wmi 模塊來實現對 Windows 服務的監控。本文將介紹如何使用 Python 監控 Windows 服務,并實現服務狀態的查詢和服務啟停功能。 安裝依賴 在使用 wmi 模塊之前,需要先安裝 wmi包。可以使用…