一文揭秘饿了么跨端技术的演进、实践与落地 - 阿里技术

本文会先带领大家一起简单回顾下跨端技术背景与演进历程与在这一波儿接着一波儿的跨端浪潮中的饿了么跨端现状,以及在这个背景下,相较于业界基于 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 中有遇到任何问题,欢迎在后台回复【 MorJS 】加入社区服务群反馈、交流和学习。

展望未来

未来,在现有的 MorJS 的能力基础上,我们会进一步完善已有的多端能力,提升多端转换可用度,完善对各类社区组件库的兼容,并持续扩展编译目标平台的支持(如 鸿蒙、快应用等),在持续为饿了么自身业务和社区用户提供高质量服务的同时,期望有朝一日 MorJS 可以成为业界小程序多端研发的基础设施之一。

4