终端容器无关化(Containerless):与服务无关化(Serverless)的概念类似,即在保持顶层业务研发语言不变更的情况下,在下层可以兼容性地升级、替换终端容器的能力,让用户无需关心终端容器的运维,只要将精力聚焦到业务逻辑上的技术。
一、前言
React2X是一款面向多终端、跨平台、容器无关化研发框架。在整个美团前端技术栈日益规范的趋势下,React技术栈在我们技术体系环节中的地位变得越来越重要。在广告、营销这些推广属性的业务上,在各个终端(包括美团App、美团外卖App、大众点评App,以及站外的微信小程序、百度小程序、头条&抖音小程序等其他终端)实现“一次开发,同步需求上线”的业务诉求也变得越来越多。在这样的背景下,我们定义了React2X应用的核心场景:
- 面对美团内部丰富多样的技术容器体系(Mach、MRN、Titans、MTFlutter、Tango、MMP等,见文末术语解释),如何保证跨容器开发体验的一致性,以及建设跨容器应用开发的生态能力,是我们需要解决的问题。
- 公司内丰富的终端容器化技术蓬勃发展,而因业务升级带来的改造成本也比较大,亟待一款高扩展性设计的顶层框架作为技术抓手。
- 跨容器动态化能力覆盖,逐步成为各个业务方越来越重视的基础能力,可以大幅缩短需求交付的周期,提高上线发版的效率,并能有效地解决包体积大小的问题,提升业务的敏捷性。
- 多场景下的同构诉求,例如在各种推广页、模块化、游戏同构,还有轻量布局差异的PC/App同构,可以节省多端研发的人力。
最终,我们的核心痛点围绕在美团系·小程序和美团系·App矩阵的“同一个需求的多次开发运维”上。为了解决研发人力瓶颈的问题,我们需要开发一款“一次研发,多终端容器复用”的研发框架来提升研发效率。
通过调研,我们找到了业界的一些解决方案,像是美团最早的mpvue、腾讯的WePY、滴滴的Chameleon、京东的Taro等等。经过比较和试用,然后基于投入产出比的判断,最终我们选择“站在巨人的肩膀上”研发定制一款满足美团技术、业务场景的研发框架——React2X(下文简称R2X)。从R2X第一个版本发布,一直到现在,已经接受了美团内部多个业务线两年多的时间考验。希望通过本文让大家对R2X有一个大致的了解,我们也希望开发过程中的这些思考和经验,能够帮助到更多的同学。
二、目标与场景
2.1 核心目标
为了解决业务需求在多端容器需要重复开发的难题,通过代码复用实现开发提效,我们确定了以下的目标:
- 解决公司内部多终端容器开发痛点:实现Webview容器、小程序容器、MRN容器、Mach容器、游戏容器、部分运营推广场景PC容器的代码同构复用,统一开发规范,抹平开发差异,并提供对其他容器的扩展能力。
- 建设跨容器动态化能力:跨容器动态化能力的缺失,导致产品不能够通过快速迭代来验证需求的效果,这个问题严重限制了业务的发展。跨容器动态化能力可以解决美团外卖业务客户端发版限制和小程序包大小限制的问题,帮助业务实现快速发版上线以及线上问题热修复的能力。
- 建设容器无关的开发生态体系:R2X最终要解决的是容器差异性,进行统一的技术生态能力建设,为多终端容器开发场景提升生产和运维效率。
2.2 应用场景
R2X开发框架主要期望能最终面向多终端应用的终端容器,用于场景化研发:
即:
- 业务项目基于React语法为技术框架基础。
- 业务方有在多终端/多容器(包括MRN容器、Webview容器、MP容器、Flutter容器、Mach容器、PC浏览器容器)运行的需求。
- 业务方有特定的场景化诉求,包括推广页、模块化、小游戏、PC/App同构等等。
三、业界方案
针对上述核心目标和应用场景,我们对市面上的跨容器框架进行了调研。由于美团外卖的技术栈统一是React为主,所以我们的必备要求是:一款以React为DSL语言的复用框架,能快速融入美团的技术生态。
根据下表的对比,如果以React为DSL语言出发,当时就只有Taro一家能满足我们的业务诉求,但它的生态环境并不适合在美团体系内使用。基于多方面因素的考虑,我们决定结合各大主流框架之所长,然后开发出一款属于美团外卖的跨容器复用框架。
对比项 | mpvue | Taro 1.3 | Chameleon | WePY | UniApp |
---|---|---|---|---|---|
DSL | Vue | 类React(Nerv) | 类Vue | Vue | Vue |
是否支持 React Native | 否 | 是,但支持效果不佳 | Weex | 否 | 否 |
兼容 API | 无 | 有(API支持程度不一) | 自研多态协议 | 无 | 是 |
跨端组件库 | 无 | 有 | 有 | 无 | 无 |
美团生态 | 有 | 无 | 无 | 无 | 无 |
语法校验 | 无 | ESLint | 自研 | 无 | 有 |
TypeScript | 有 | 有 | 无 | 有 | 有 |
定制化扩展 | 无 | 可自研Plugin | 无 | 无 | 有 |
编译扩展 | 无 | 无 | 无 | 无 | 有 |
调研结论 | 不匹配 | 部分满足 | 部分满足 | 不匹配 | 不匹配 |
注:前期调研时间截止到2019年05月,可能与当前数据存在一定的出入。
四、挑战与优势
4.1 项目难点
当我们决定要打造一款属于美团外卖的跨容器复用框架之后,在实现的过程中主要遇到了以下四个方面的挑战:
① 各个容器之间差异性适配成本
- MRN/小程序/Webview在DSL上有着完全不同的语法,在各容器的Native能力上更是差异巨大。
- 同一容器在不同端上也存在不少的差异,比如美团外卖App中MRN容器和美团App中MRN容器之间,就有Native模块、通参协议、KNB桥协议等不对齐的地方。
② 类小程序容器的转换复用
- 小程序容器以WXML和JavaScript相结合实现页面渲染,与React这种纯JavaScript声明式语法难以进行结合,如何突破限制是一大难关。
- 小程序容器以微信小程序为首,衍生了很多其他类小程序容器,如何与它们进行复用也是一大挑战。
③ 业务接入的使用成本
- 作为一个新定义的框架,如何让业务方快速上手,如何从旧业务线进行迁移。
- 如何融合美团的基建生态,让业务方快速进行接入。
④ 顶层架构的合理设计
- 框架整体设计的高可维护性、高度扩展性。
4.2 项目优势
4.2.1 功能特点对比
目前,业界以小程序作为跨端目标平台的框架较多,但大多都是使用Web前端技术栈作为基础,但同时兼顾React Native的技术栈就比较少。下表中列出的是支持以React、类React作为DSL的相关框架进行对比。
R2X | Taro 1.3 | Taro 3.0 | Rax | Remax | |
---|---|---|---|---|---|
原理 | R2X 1.0重编译时,R2X 2.0重运行时 | 重编译时 | 重运行时 | 重运行时 | 重运行时 |
容器重点 | 以MRN,小程序,WebView为主,同时支持MTFlutter、Mach、游戏、PC浏览器 | 以小程序、Web为主,React Native支持不多 | 以小程序、Web为主,React Native交给58团队支持 | 小程序、Web、Flutter | 小程序、Web |
API | 支持KNB桥&对多平台API进行了统一 | 对多平台API进行了统一 | 对多平台API进行了统一 | 多平台不统一 | 多平台不统一 |
跨端组件库 | 有 | 有TaroUI,但不支持React Native | 有TaroUI,但不支持React Native | 无 | 无 |
业务组件扩展 | 提供扩展方案 | 参考TaroUI | 参考TaroUI | 提供扩展方案 | 提供扩展方案 |
美团内部生态支持 | 已支持埋点监控等 | 无 | 无 | 无 | 无 |
模块化能力 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
小程序动态化能力 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
编译插件扩展 | 支持 | 不支持 | 支持 | 支持 | 支持Webpack配置 |
综上所述,从目前的业务形态来看,R2X在容器的匹配程度以及美团生态支持程度上看,是现阶段的最佳方案。R2X相较于业界其他框架来说,拥有更加完善的适用于美团外卖团队的本地化实现。
4.2.2 性能数据对比
基于业界跨平台框架和美团内部的跨平台框架,我们针对性能也进行了Benchmark测试,最终对比结果如下。
小程序性能对比
框架 | 创建 | 更新 | 添加 | 交换 | 删除 |
---|---|---|---|---|---|
R2X-MP | 947.6 | 586.8 | 1467.2 | 1355.2 | 82.2 |
Remax | 2798.2 | 1872.6 | 5162.2 | 4818.2 | 86.4 |
Taro-MP | 1653.4 | 976.4 | 2483.2 | 2256.6 | 65.2 |
结论:可以看到,在小程序Benchmark测试结果中,R2X领先于Remax和Taro。
与React Native性能对比
框架 | 创建 | 更新 | 添加 | 交换 | 删除 |
---|---|---|---|---|---|
R2X-MRN | 309.875 | 83.75 | 384 | 191.875 | 82.125 |
MRN | 297.625 | 105.25 | 400.125 | 231.625 | 65.875 |
Taro-RN | 209.5 | 77.5 | 246.25 | 85.125 | 17.125 |
结论:在React Native的Benchmark测试结果中,R2X和MRN基本持平,但都低于纯React Native的性能表现。
4.2.3 同构场景对比
除了支持了基本的React Native、小程序和Webview容器同构场景之外,R2X还实现了在MTFlutter、Mach、小游戏(H5游戏、微信小游戏&小程序、美团小游戏)、PC浏览器等容器上的同构能力扩展,相比于业内的其他跨容器开发框架的生态也更加丰富和健全。
React Native | 小程序 | Webview | Flutter | 模块级容器 | 小游戏容器 | PC浏览器(PC/App同构) | |
---|---|---|---|---|---|---|---|
R2X | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
Taro | 支持 | 支持 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
Rax | 支持 | 支持 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
Remax | 支持 | 支持 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
五、技术全景
上图为R2X的架构全景图,整体架构可以按照从下到上,从左到右的视角进行解读:
- 最下层是R2X的生态环境建设,在R2X内部去实现公司生态的常用SDK以及业务中的各项专题能力;并通过搭建物料市场/插件市场,以业务共建的形式丰富R2X生态。
- 再上层是R2XCore的根基,通过解析Command命令来执行唤起构建器,并实现了类似Webpack的插件系统,以插件化的形式组织驱动整个核心构建流程,便于维护以及扩展。
- 再往上是跨端容器层,它是整个跨端能力的核心,通过实现了不同的容器插件来将R2X代码编译成各端可执行代码,并通过运行时能力对组件/API进行对齐。
- 最上层是承载的App端,目前有美团外卖、大众点评、美团等多款移动App终端。
- 最右边是R2X在研发、发布、运维以及用户文档上做的一些建设。
因为R2X覆盖了美团内部大部分的主流容器场景,所以技术体系较为复杂和庞大,大家可以根据自身的业务形态,选择性地去了解对应场景的同构方案。
5.1 底层基础框架
5.1.1 R2X-CLI的设计
CLI作为R2X项目驱动器,它不仅包含了命令行的启动,更重要的,它是各个编译构建的核心。
在早期,CLI执行build命令时,我们通过–type来区分不同的构建容器,从而加载不同的编译逻辑。通过指定构建容器的形式来实现同一套代码能够构建出不同的容器产物。但经过长时间的业务迭代,我们发现了这种结构存在的问题:
- 整体流程冗长且复杂,长时间迭代会变得越来越难以维护。
- 每个容器的构建流程相互独立,且构建逻辑各不一致,有多处重复的逻辑处理。
- 编译流程缺少统一的关键节点,编译时无法进行业务方的定制扩展。
针对以上问题,我们考虑对CLI进行了一次全新的重构,引入插件化能力(关于插件化能力的具体实现会在下文详细描述)。CLI整体结构变成如下图所示:
整个CLI模块只需要关心参数的解析以及插件的加载执行,不需要再实现各个容器的具体编译逻辑。通过Hooks的形式,将编译的各个时机暴露给插件,插件基于这些Hook进行编译能力的实现,最终输出产物给CLI模块。这种形式带来了以下几个好处:
- CLI结构变得清晰,只需要维护配置解析、插件解析等功能。
- 扩展性增强,可通过插件化的形式新增或删减容器/编译能力,保证代码独立维护功能的单一性。
- 编译流程可梳理,无论什么容器的编译流程都基于编译器暴露的时机执行并串联,整体流程清晰明了。
5.1.2 组件及API的设计
R2X的目的是希望通过一套代码能够在多端上运行,但是由于多端差异的存在,我们需要设计一套统一的标准规范来进行对齐。在运行时部分,主要分为组件/接口的对齐。
多端差异
在开始讲述实现之前,我们先来看看各端之间的差异到底在哪些地方。
组件(标签)差异
- H5标签采用的是XML写法,所提供的基础标签有<div/><a/>等等。
- 小程序采用的是WXML(WeiXin Markup Language)标签语言,也提供了一套完整的基础标签,但是和H5有着较大的差异。
- React Native则是采用的JSX语法,虽然和XML很接近,但是又有着很多的不同点,同时它也有自己的一套基础组件,和H5、小程序又截然不同。
API差异
- 接口差异:在不同端中都提供了相同或近似的功能,但是其实现方式以及调用参数可能存在着很大的差异,比如数据缓存Storage,小程序中用wx.setStorage/wx.setStorageSync,H5则用localStorage.setItem,而MRN中AsyncStorage.setItem,几乎每一个功能点都有着多多少少的差异。
- 容器差异:各个端所提供的API都是各自的容器量身打造的,比如小程序的用户接口类API、广告类API,完全是针对小程序所处的微信环境打造的,这类功能对于其他端来说是完全不相干的东西。
- 能力差异:各个端之间的差异我们可能通过定制的手段来适配,然而并不是所有的功能点在各个端上都能够实现。比如在H5中就无法做到像小程序、React Native中提供很多原生能力,像是文件保存读取等等,这一类差异性在适配过程中都属于不可抗拒、不可抹平的差异。
样式差异
小程序的WXSS和H5的CSS在参数属性上其实是几乎一致的,但是在层级关系上有着很大的差别,小程序分为全局样式与局部样式,各个组件之间的样式也是不会相互影响(默认配置下)。而对比React Native采用的StyleSheet,是用Inline Style的方式,不支持全局样式,不支持标签样式,并且属性有诸多限制,如只能使用Flex布局等等。
如何适配?
根据上文,我们已经了解到了各个端之间有着非常大的差异点,那我们应该如何克服这些困难呢?
由于各端对组件和API的支持程度不同,我们选定了一端为基础标准,定义好各个组件的属性以及接口参数,通过TypeScript的Interface进行实现。然后在各个端分别基于以上的接口进行功能对齐实现,对于端能力限制的功能进行了一定取舍,对高优功能进行了SDK底层实现适配。最终,我们基于已有的功能封装实现了一套完整的基础组件@r2x/components
和基础API@r2x/r2x
。
5.1.3 开放式插件能力
随着R2X的在美团内部的应用越来越多,大家对于R2X模式的认可度也在不断提高,我们从业务方中经常听到以下这些问题:“是否可以增加支持某某功能/容器”,“我们业务架构比较特殊,能否做出一些调整”。业务方对R2X会有更多功能/容器的诉求,也会有更多定制化的需求出现。
所以,我们决定实现一套完整的开放式插件能力,提供一种相对比较简单的方式,让大家能够自己来定制这些特殊需求。在最新的版本中,我们将R2X的编译时进行了重构,在新的编译时架构中引入了基于Tapable的插件系统。开发者可以通过编写插件的方式为R2X拓展更多功能,或者为自身业务线定制更多的个性化功能。
在插件类型分为两类:
- 容器插件,用于封装R2X所支持的容器的核心编译能力。
- 功能插件,基于已有的容器插件,在此基础上进行某种特定功能的自定义实现。
插件能力的整体架构如下:
借助开发式插件能力,我们将之前编写了若干个平台容器插件,开发者安装后即可使用:
- 微信小程序插件:@r2x/plugin-container-wxapp。
- MRN容器插件:@r2x/plugin-container-mrn。
- H5/Titans容器插件:@r2x/plugin-container-h5。
当然,用户也可以基于开放式插件能力,参考现有的容器插件自行扩展一个容器:
- R2X支持Caster(美团小程序动态容器)容器插件:@r2x/plugin-container-caster。
- 到店广告H5容器插件:@dp/plugin-adp-h5-component。
除了扩展新的容器平台,我们还可以通过继承现有的容器插件,来编写一些特殊的定制化功能插件。
1. 对代码进行预处理
基于开放式插件能力,我们可以像Babel插件一样,通过对AST语法的修改对代码源文件进行编译前后的修改。比如:修改文件引用路径、插入代码片段、处理本地图片等等。
2. 对文件产物进行修改
在编译产出生成时,我们可以对编译文件的内容、文件路径、文件结构进行修改。结合自身业务的定制化,CLI可以将R2X项目和现有的原生项目进行结合改造。
除了以上功能,插件化能力为用户在编译时提供了极大的自由度。如果你想体验的话,欢迎加入美团外卖技术团队。
5.1.4 特性能力-多态能力
为什么需要多态能力?
多态能力是用于提供跨端时各端组件及API的统一解决方案。基于多态能力,开发者可以定制自己的跨端组件。而R2X具备了完善的跨端能力,能够覆盖多终端和容器,为什么还需要多态?
“技术作用于业务,但业务逻辑不会跟着框架走,有时候开发者需要突破框架的限制。同时,H5/小程序/React Native存在端上的差异,需要开发者人为进行环境判断。逻辑一复杂、跨端数量一多,代码可读性变低,维护成本起飞,这不是我们的本意。”
基于这样的背景,R2X提供了扩展性良好的多态能力。
R2X多态能力介绍
对于多态能力的支持,我们分为两类:
- 多态组件/API,R2X根据文件后缀区分编译目标端。
- 差异化代码,R2X提供getEnv方法用于判断当前语句编译目标端类型。
<View style={{color: R2X.getEnv() === "WEAPP" ? "green" : "blue" }} />
通过差异化代码可轻松满足端差异诉求。
5.1.5 生态支持-发版部署
发版部署作为R2X生态闭环的最终环节,肩负着将多端项目上线的重任。多端发版部署,最重要的是支持灵活配置。R2X发版部署过程基于Talos(美团内部自研的部署工具)实现,开发者经过可视化配置即可部署至指定容器中。
开发者首先配置该项目需要发布的端,其次只需要配置发布的相关容器信息即可。经过指定端的编译后,会将代码部署至相关平台:H5部署在S3(美团内部自研的文件存储),React Native部署在DD(美团内部自研移动端动态下发平台)。对于需要部署至线上环境的R2X项目,我们也接入了ED(美团内部自研持续交付系统),由发版值班同学统一执行部署,规范化发布的流程。
5.1.6 生态支持-监控运维
由于Raptor(美团内部面向基础设施和端到端应用程序的监控平台)目前不同容器的监控SDK使用存在差别。我们需要在R2X框架内对其进行进一步的API抹平,减少用户的使用和学习成本。通过封装R2X/OWL模块,通过在运行时调用不同的API来抹平其差异,来实现多端统一监控。最终的监控框架如下图所示:
5.2 应用场景同构
5.2.1 页面级容器场景同构
MRN、小程序以及H5的页面级容器同构方案,在这里不过多赘述,和业界的开源框架实现思路大同小异。下面将重点介绍一下我们在小程序动态化能力方面做的事情。
小程序动态化同构
在小程序动态化能力建设方面,R2X与Caster和Tango(外卖小程序动态容器)在能力共建上达成一致,实现了R2X在两种小程序容器上动态化能力的接入。R2X小程序动态化核心结构分为3层:
- 应用层:应用层遵循R2X DSL规范,业务侧根据该规范编写自己的多端业务逻辑。
- 编译器:预编译层负责将JSX/TSX转换为标准的JavaScript代码,并根据R2X多端协议处理小程序业务逻辑(涉及到环境变量的替换,依赖的替换或处理等),最终将所有的业务逻辑编译成为AST文件,部署到云端。
- 运行时:Caster与Tango虽然因为定位差异采用不同的运行方案,但是整体范式基本相同;概括来讲,两者都是通过JSVM将云端拉取的AST文件解释为可运行的JavaScript代码,再由特定的渲染器进行UI渲染;核心差异在于Caster内部通过微信的Kbone来模拟浏览器环境进行渲染,而Tango通过react-reconciler生成类VNode树,再利用小程序的template模板能力来进行渲染。
R2X动态化编译核心流程如下:
① 读取配置参数,为后续构建提供信息。 ② 处理非动态化部分,调用R2X小程序的编译流程生成app.json/app.js、project.json等基础项目信息。 ③ 执行编译流程,Caster(美团小程序动态容器)和Tango(外卖小程序动态容器)的编译流程存在部分差异。
a.Caster编译流程 1. 安装Caster SDK。 2. 使用Caster API生成动态化基座。 3. 将不需要动态化的本地依赖和不能动态化的原先小程序组件复制到基座当中。 4. 使用rollup将动态化组件打包成JS Bundle,并写入磁盘。
b.Tango编译流程 1. 安装Tango SDK。 2. 使用Tango SDK的API 将动态化页面编译成AST,并写入到磁盘(备注:Tango 相对于Caster少了生成动态化基座的流程,因为在外卖小程序当中已经对动态化基座进行了内置,并且集成原生组件时,需要和基座开发人员进行沟通,将原生组件进行集成,所以在Tango当中应改尽量避免使用原生小程序组件。)
5.2.2 模块级容器场景同构
在模块级动态化同构方案上,我们在客户端底层上依赖Mach容器。在小程序容器中,我们克服了Mach为了追求高性能摒弃了React运行时、JS VirtualDom所带来的困难,单独为Mach小程序容器设计了渲染方案,实现了R2X-Module在客户端和小程序上99%以上的代码同构率。
整体方案
- 核心驱动包,容器驱动的核心,针对渲染能力、解析能力、缓存能力、性能监控四个方面进行了实现,达到动态化驱动效果。
- 业务容器自定义,基于SDK提供的驱动能力,针对不同展位特性进行了容器自定义功能扩展配置,让业务方可根据实际业务场景自行扩展。
- 分环境构建,主要实现了将类React语法进行AST编译解析,根据构建平台分别编译成对应的Bundle产物。
- 自动化构建部署,将构建能力接入Talos,再结合Mario等工具实现一键部署,将编译产物根据配置项上传至DD平台。
模板驱动方案
目前,R2X-Module在客户端和小程序容器的同构能力,已经在闪购业务上完成落地,已上线3个模板的同构率在99.3%以上,在性能方面首次渲染时长和模板渲染时长的TP50时间分别是185ms和144ms,比较优秀,但还存在可优化的空间。外卖小程序R2X-Module SDK的接入正在测试中。R2X-Module SDK初始化以及模板加载渲染流程入下图所示:
5.2.3 PC/App适配同构
在移动互联网发展已经高度成熟的今天,移动端的PV流量占比绝大数,以外卖广告商家端为例,PC端仅仅占有很少比例,其中PC流量占比在我们部分业务上已经不及5%。因此在某些场景下实现PC/APP的同构方案能够解放一部分人力,对提高开发效率来说是十分必要的。目前,外卖广告商家端的一些轻量布局差异的页面,已经完成了PC/App同构的方案设计和落地。
样式同构适配
端能力扩展
R2X的基础能力支持H5/MRN/微信小程序三端,缺少对PC微前端子项目的支持。要实现PC/App多端同构,需要对R2X的端能力进行扩展。PC端本质上也属于Web端,因此PC微前端的端能力扩展可以复用大部分的H5的端能力。整体架构图、技术设计要点、扩展流程图如下所示:
平台代码处理
在项目同构开发中,不可避免地会出现跟平台强相关的代码或者业务逻辑,比如某些API调用的是App的底层能力,只能在React Native中使用,在Web端肯定是不支持的。或者由于产品需求的原因,某些交互或者展示差异较大等等。而项目针对某一端进行编译、打包时,其他不相关的端代码是无用、多余的,如果保留的话,不仅会增加代码体积,甚至会出现编译报错,因此我们需要借助平台代码处理的能力来进行优化。平台代码的处理主要包含三部分:模块导入、组件展示、业务逻辑。
主要思路是使用注释和指定平台的方式,让特定的平台代码只在特定平台生效,注释关键字%%platform%%
, 比如%%RN%%
表示React Native端独有,%%MICRO%%
表示PC微前端独有,%%MICRO|H5%%
表示PC微前端、H5 两端生效。示例代码如下:
import A from '@r2x/r2x-a'; // %%RN%%只在React Native端保留。
import B from '@r2x/r2x-b'; // %%MICRO%% 只在MICRO端保留。
import C from '@/utils/c'; // 这是所有端生效的公共模块。
import D from '@r2x/r2x-d'; // %%MICRO|H5%%在MICRO、H5多端生效的模块。
5.2.4 小游戏容器场景同构
实现react2x-game同构方案主要做的两点:渲染层的兼容、业务层的兼容。
- 渲染层的兼容:实现游戏引擎在多端环境下渲染能力的兼容(Canvas、WebGL)。
- 业务层的兼容:实现基础API、项目流程、公共模块的兼容,制定游戏差异的个性化定制规范。
1. 渲染层兼容
在上文,我们提到过“无论是H5游戏、小程序、小游戏、美团小游戏都为我们提供了Canvas、WebGL控件”,很大程度地降低了我们兼容渲染层的复杂度。下面表单,是各端对于语法以及Canvas、WebGL、Document、Window等基础功能的支持情况:
对象 | Webview | 微信小游戏 | 微信小程序 | 美团小游戏 |
---|---|---|---|---|
语法 | JavaScript | JavaScript | JavaScript | JavaScript |
Canvas | 支持 | 支持 | 支持 | 支持 |
Canvas(离屏) | 支持 | 支持 | 不支持 | 支持 |
WebGL | 支持 | 支持 | >2.11.0 | 支持 |
Ducument | 支持 | 不支持 | 不支持 | 不支持 |
Window | 支持 | 不支持 | 不支持 | 不支持 |
可以看出,在语法层面各端都支持了JavaScript语法,但是在执行环境以及基础功能上的差异比较大,总结来说:
执行环境:小游戏、小程序不具备DOM、BOM的能力(渲染引擎中会大量使用)。 基础功能:小程序不支持离屏Canvas,在2.11.0版本以后才开始支持WebGL。
为了解决这些问题,我们设计开发了adaptor层,用来模拟document、window的能力。使游戏引擎可以在非H5的环境下正常的执行和调用BOM、DOM的基础功能。同时,制定离屏canvas的适配方案,用来解决小程序无法支持离屏canvas的问题。为了获取到有效离屏canvas,我们制作了 “r2x-add-wxml-loader” ,在.wxml文件的loader阶段自动注入额外的< canvas/ >控件,并隐藏于手机屏幕之外,用于模拟游戏引擎中的离屏canvas。
2. 多端兼容构建
在构建层面,我们通过集成的多种个性化插件工具,对多端代码进行差异处理。如:环境变量注入、各端适配代码的混入、规范检测、代码解析和转化等。针对小游戏、小程序代码和执行环境的特殊性,制作wx-build-plugin、lwxapp-build-plugin等用于处理小游戏和小程序的打包工作。结合上文中提到的各类差异的处理方案,制作add-wxml-loader、transfrom-loader、wxss-loader等工具协助完成项目构建。如下图17所示,构建之初会注入本次构建的环境变量,读取和分析配置文件,集成和初始化构建工具集合,为项目构建做准备。然后在构建环节,针对各端的差异进行差别处理,分析层针对不同文件进行解析,并在转换层进行转换和构建,最终生成各端需要的最终产物。
5.3 落地场景与效果
5.3.1 落地场景
5.3.2 效果收益
R2X在美团外卖业务中得到了广泛的应用。截止2021年10月,R2X累计在美团内部已有二十多个部门在使用或者在调研中,总计落地了上百个工程、页面,框架下载量达百万次,页面平均代码同构率达90%以上。R2X生态体系在容器代码复用与运维层面,累计为美团节省成本上千人/日,并提升动态化页面转化5%-8%的成功率。
六、展望与总结
综上所述,在美团外卖多元化业务形态和容器多样性的情况下,跨容器复用成为了发展的必经之路。而R2X在经历了两年的迭代下也取得了阶段性的成果,在美团各个业务场景都完成了业务的落地覆盖,针对公司的生态环境接入也做出了不少的基础建设。我们相信跨容器多端代码复用依旧是当前缩减项目交付周期,减少研发成本,提升研发效率的重要一环。但目前我们在很多复杂的业务场景下做的不够完美,因此还有许多工作待完善,例如:
- 开发体验优化,目前想接入或正在接入的兄弟部门已经越来越多,如何减少接入成本、丰富基础建设、优化开发体验、帮助大家快速迁移接入将是下一阶段的重要课题。
- 渲染性能优化,在美团外卖场景下,性能优化一直是我们在兼顾高效生产的另一个重要指标。在小程序动态化场景下,动态化方案React渲染器对性能有一定程度限制,如何突破这一难关将会是动态化全面推广的“敲门砖”。
最后,感谢各个相关研发团队对R2X建设过程中的鼎力支持,R2X的发展离不开所有参与者日以继夜的投入和贡献,我们会持续基于R2X在终端容器领域进行更多探索。如果您觉得R2X还不错,或者对美团的R2X框架比较感兴趣,欢迎跟我们一起交流探讨。
作者简介
正浩、宝石、彭震,均为美团外卖终端团队研发工程师。
招聘信息
美团外卖长期招聘Android、iOS、FE、Java高级/资深工程师和技术专家,欢迎有兴趣的同学投递简历到lizhenghao@meituan.com。
如发现文章有错误、对内容有疑问,都可以关注美团技术团队微信公众号(meituantech),在后台给我们留言。
我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!