素材巴巴 > 程序开发 >

美团前端研发框架Rome实践和演进趋势

程序开发 2023-09-13 07:33:58

本文整理自美团技术沙龙第76期《大前端研发协同效能提升与实践》,为大家介绍了美团到店前端研发框架Rome实践和演进趋势。

具体来讲,本文首先介绍了Rome整体的工程生态、演变路径、规模化升级以及工程框架外的开发辅助工具;第二部分,重点阐述了如何做框架度量和相关的业务实践;最后做整体的总结以及对工程框架的下一阶段的思考。希望能对大家带来一些帮助或启发。

  • 2 工程生态、演变路径和规模化升级

  • 3 框架开发辅助

  • 4 框架度量和业务实践

  • 5 总结及工程框架趋势思考

  • 1 背景介绍

    | 1.1 业务背景

    首先介绍一下业务的背景,这里主要从3个维度展开。第一个维度是组织维度,在立项之初,恰逢美团的多个事业群合并,因前端规模比较大,横向的流动协同比较多(需要跨部门支持需求,进行跨系统协作等等)。此外,美团到店事业群新人比例比较高,校招和新员工比例很高,我们会帮助新同学快速融入团队,需要完成一些较为基础的开发工作。

    9a4df88b186f99d384e4f17c320433dd.png

    第二维度是业务维度,美团到店业务迭代频次比较高,基础工程框架不仅要保证交付速度快,同时还对质量有很高的要求。

    第三个维度是系统维度,因业务周期比较长,到店还存在大量的存量系统,需要考虑迁移升级和重构等问题,同时会有频繁的系统交接。

    | 1.2 技术背景

    在Rome整体立项时,我们已经准备好了相关的基础设施,包括发布系统的收敛、基础架构,统一为基于S3(美团内部存储服务)加动静分离的技术架构,但是上层开发框架、组件类库种类繁多且开发方式不统一。存在问题包括:整个团队中人数比较多,学习交接、建设维护成本相对较高,而整体开发的效率比较低,跨团队之间的工程能力也很难进行复用等等。

    0d5b2855a24c8b5fb3b599dff90ab6a4.png

    建设之初,我们基于纯静态S3(美团内部存储服务)架构进行前端框架的建设,这源于我们早期大量基于Node.js的前后端一体架构存在一些问题:首先,事业群早期以中后台场景业务为主,对页面的秒开、SEO的诉求比较低;其次,当时Node.js生态基建还没有那么完善,前端同学需要做动态扩缩容、峰值流量处理等操作,整体的业务风险比较高。同时还存在机器成本高、开发人员能力要求高、招聘难度大等问题。

    因此,在整体的建设思路和路径上,我们不会建设类Egg.js这样的前后端一体的框架;同时因为我们的框架层要解决研发流程不规范、交付质量不高等问题,也需要联动上下游的设计研发、CI/CD等系统形成一体的开发工程平台,而不只是做CLI工具。

    2 工程生态、演变路径和规模化升级

    | 2.1 工程生态

    2.1.1 降学习成本

    框架约束

    根据前文所述,我们一开始要解决的核心问题是学习成本,因此我们会做框架约束。

    Rome在这一侧的解法:

    5278b7b88d52c3698fb337f18b878436.png

    跨技术栈开发认知一致

    在实际迭代的时候,到店内部一开始整体收敛到Vue技术栈,后来因团队合并,又有了React技术栈。我们采取的第一个策略是把Vue和React整体目录保持大家认知的一致,如下图所示。而在真正开发的时候,比如配置子目录SRC下,当一个同学一开始是偏Vue,但开发React需求的时候,即使团队和业务有一些变动,TA也可以准确拿到项目快速启动,接下来摆在TA面前的可能就是特定技术栈下,对于对应的API理解是否深入的问题,这部分同学自己就可以解决。

    第二是我们会保证使用Rome开发框架的整体开发调试流程和体验一致。如下图,在Vue或React框架中同学专注业务开发就行,基本上可以不用关注工程框架的相关事情。比如Vite在Vue或在React指令和表现是一致的,同学可以通过一行命令直接开始调试对应项目并进行开发。

    ad8dfb2f58ba0df2f795aba67a48314b.png

    第三,我们的整体工程能力会进行高度对齐,如上图所示。我们生态下80%的插件在Vue和React下,用法和表现完全一致,大家基本上不用关心这部分,当真正用到某部分能力,详细看对应的文档就行。

    基础基建对接

    工程能力:一行代码引入公司基建(CDN容灾)

    当前端同学处理如CDN厂商故障等问题时,需要自行查找、学习和使用公司/开源的基建能力,解决成本较高,但在Rome开发过程中可以通过开闭式的配置一键CDN容灾生效,如下图,接入后会自动进行静态资源的降级重试,当业务出现故障时(即下图峰值部分),它会有一个明显的资源加载重试,这就是降级CDN在生效;对业务同学来说只需配置框架需要哪个能力就行,其详细配置如何注入大家并不需要太关注。

    366947bf225457875605ec26b8ecd0e2.png

    工程能力:一行代码引入公司基建(告警监控)

    业务开发以外的像告警监控,对同学来说,可能也要理解很多东西。但是在企业内开发,我们希望同学可以专注业务开发,像线上告警、日志链路等出现问题,可以不用配置对应平台,我们用对应的项目Key就可以查到对应的错误总量、错误调用链路等。

    3b57d32c9ed096be5212cd92e177a36e.png

    工程能力:一行代码引入公司基建(水印)

    我们也可以一键完成对应的水印接入,同时开发配置时有对应的配置项智能提示。各种开闭能力的属性命名语义可能没那么清晰,可以通过如VSCode中的智能提示一键跳转到对应能力的文档地址,查看它的实现原理以及使用方法。

    380dfcdbe7818141ffdda08f5dc4348d.png

    2.1.2 降建设成本

    之前组织下建设的很多能力是偏小蘑菇的形式,“小蘑菇”的语义是整体工程能力的生命周期比较短,会进行频繁的重复建设。但我们希望以一个大树的形式建设,“大树”的语义是我们可以通过跨团队、横向方式进行高质量的设计和建设,通过评审委员会把控整体的方案建设,把方案拆分到几个阶段,横向团队共建,共同完成核心能力,比如Serverless、SSR等。

    工程能力生态

    如果大家对工程框架的建设能力感兴趣,可以参考我们内部的效率、质量、体验和领域实践进行对应分类的建设。我们通过一线调研、能力盘点的方式建设了31个,在企业内进行建设时,有很多能力一开始可能本身成本就很高,比如统一基建接入等,大概需要 30人力/个,而实际业务需求开发一共只有几天时间,很难说服产品运营单独抽出大量人力开发前端基建能力,这部分我们就以共建+横向评审的方式,保证业务团队可以摊平整体的建设成本。

    48a828c35ecf15cc74ca1b571008a9e2.png

    典型共建案例

    Serverless SSR能力,在休娱频道的密室和优选团长端的订单管理流量分别是百万级别和千万级别,整体秒开可以做到90%左右。

    15e0f5c146d70b60fa24848f2db4b2ce.png

    整个过程是Rome + Arche团队共建并形成到店标准,业务统一落地,过程中有超过3个业务团队参与了部分能力建设。

    这里简要介绍下Serverless的方案流程:

    首先是访问自动降级,用户通过负载均衡命中对应的网关,命中对应的Serverless的Node Runtime,这里会有对应页面粒度的SSR渲染函数,当用户访问服务器返回 5.x.x 状态码或超时时会自动降级到CSR资源(SPA页面);即使出现了极端情况,比如 SSR 服务异常,我们也可以保证整体页面可用,差别主要在 SSR场景秒开~90%,CSR场景秒开~30%,兼顾了性能和稳定性的优势。

    其次是支持页面粒度接入,在大型 MPA 项目开发中,可以把某个页面单独设置为SSR,不必要求整个项目都是SSR工程,构建时默认会上传CSR端构建资源,而针对SSR页面会额外进行另外一份资源的构建,在部署SSR端、CSR端资源时分别部署,用户访问页面链接时,对应命中Server端或者CDN资源。

    支持自动扩缩容和流失渲染,对接公司Nest基建,支持业务无感知的峰值流量自动扩缩容;同时长列表页面也可以通过流式渲染来降低TTFB时间。

    19e3537219edb4c721cf8fb77b7ab01e.png

    2.1.3 提研发效率

    编译提速主要分两个方向进行业务落地,分别是Webpack体系和Vite体系。

    编译提速 - Webpack体系优化

    首先是Webpack体系,因为我们整体的技术栈分Vue和React两部分,我们会抽一部分基础的跨技术栈的Webpack配置,上层有不同团队分别维护Vue技术栈和React技术栈的特有配置,中间我们会进行专项优化,包括像Webpack5的开发优化、编译压缩器、SWC和esbuild等。

    另外,我们做工具时,不仅要考虑我们本身构建工具比如Webpack,也要考虑如何和我们的CI/CD平台结合,如缓存复用结合依赖安装、构建工具做,在很多需求场景下,可以获得耗时的10倍提升,CI/CD侧我们也支持分粒度的构建,比如大型MPA做页面粒度的构建等。

    15d1a45347b71c3dbcf9d6b7d970cdfa.png

    编译提速- 开发时⼀键Vite

    Vite主要是我们在开发时使用的,Webpack是构建时使用,除了少部分增量项目的开发和构建都走Vite,大多数存量项目都是开发使用Vite保证效果,构建阶段使用Webpack。

    8d954b198b361f204137ec9f52fe209d.png

    整体流程:首先是启动,通过Vite,比如createServer拉起页面,抹平Webpack差异;环境变量的抹平,保证客户端Webpack存量项目,将Webpack客户端的环境变量注入到Vite端;对配置文件,大家原本在rome.config.js中的Webpack配置也可以一键转换为对应的Vite配置;在下层我们会做内置的技术栈插件,包括Vue2/Vue3 SFC+JSX,包括React的内置插件等;比较繁琐的是生态兼容,在公司内这部分的工作量比较大,像我们的一些SaaS的静态资源的一些路径等,包括之前我们存量Webpack这么多年积累下来的公司基建,我们如何保证它能被注入到Vite端,包括组件库按需引入,当一些模块比如common.js的模块如何指向对应的esmodule目录等,最后我们会屏蔽一些认知成本,把Vue、React和公司依赖包内置到Vite预编译内容中。

    依赖提速

    主要分两部分,分别是开发阶段和部署阶段。

    首先会做工程框架自身Node.js依赖的预构建,这部分核心解决的是Node.js端公司内外包资源的体积和递归依赖数量庞大的问题。依赖安装的一个核心耗时其实是递归依赖庞杂,需要逐个安装带来的耗时,比如需要安装A,其实A依赖了B、C、D、E、F、G,整体安装耗时就会非常久,同时研发同学对Node.js包体积、依赖数量一般不如面向浏览器端投放的NPM包那么敏感,这个时候预编译就很关键。

    其次是把整体的依赖环节包管理工具切换到Pnpm。这部分经过调研(Pnpm、Yarn Berry、Yarn Berry with PNP等),判断Pnpm是未来几年的核心趋势,同时可以稳定发展。内部建设了对应的包管理迁移工具,来服务企业内几百个、上千个项目。

    0b494763c8ff91ecf83e3b2e866436eb.png

    在部署阶段定制了Rome依赖安装Docker镜像,锁Pnpm版本和内置常用依赖、缓存复用,它的整体逻辑是上一次需求迭代和下一次需求迭代可能依赖包的变化没有那么多。我们在第二次发布的时候,如果能够尝试命中上一次的node_modules里的一些包,那第二次安装耗时就会有一个比较大的提升。

    | 2.2 演变路径

    第一阶段的时候是强依赖Webpack和Vue技术栈的。直到2020年-2021年,像社区UI框架有Solid.js、Svelte、Vue3,构建工具有Esbuild、Rspack、Vite等且发展势头也比较好,面向这个大趋势,我们希望研发框架能够分层过渡,不再和具体的UI框架、构建工具绑定:

    1. 首先最底层是差异机制,核心做插件的加载和调度;

    2. 中间层是构建工具的bundler ,这一层主要是分别结合Webpack、esbuild、Rspack等构建实现,支持大量项目;

    3. 上层Plugin、Preset做框架拓展,各个业务能够基于场景定制自己的工程能力;

    4. 顶层是品牌指令(bin),这部分主要是企业内合作时业务方希望保持自己的品牌名。

    示例如下图右侧,大多数情况下,我们有一个新的研发框架出来,只需要开发我们对应的语言特色的插件集合就行,底层插件机制+构建工具大家其实可以保持一致的。

    ae2e2fd7e1f4d5959206ca4c4692aad5.png

    | 2.3 规模化升级

    框架价值=覆盖范围 * 功能价值。我们的共识是建设的能力需要落地才能产生价值,核心是帮助大家业务低成本地享受好用的能力。

    如下图所示,是某个业务的升级成本图,可以看到有100多个项目(成本均值~5pd/项目),业务面临几百天的成本。对团队Tech Lead很难说服业务产品运营业务阶段投入升级。对一线同学来说,虽然能力很多、很棒,但是升级风险怎么处理:编译提升10s,线上问题定位消耗一周。

    66bfc885b10a9c7f7f609feaba66c309.png

    这部分的我们给两个解决方案。

    首先是提供迁移工具(非Rome到Rome项目):

    1. 巨石项目做存量迁移时,一般同学下意识反应是通过Babel做静态解析迁移,纯静态解析实测的迁移准确率在40%,也就说一个项目40%的事情通过Babel可以搞定。

    2. 第二阶段是基于构建工具的依赖引用关系去做迁移,通过构建工具启动时的模块工厂钩子去生成依赖引用树状结构然后做迁移,得到迁移准确率在60%左右。

    3. 第三阶段是动态分析结合AST静态分析一起去做,在数据采集阶段通过构建工具的模块工厂钩子、Vue/React实例化对象的路由/数据流配置去生成依赖图结构,通过recast等工具进行静态解析,不用Babel是因为recast有比较好保持样式的代码回写,文件内容增删改后写回原文件样式不乱,同学在git diff时需要Code Review代码就可以少一些,便于迁移影响范围判断。

    4. 最后配备上基础公司基建做的一些依赖版本、体积、兼容性检测的质量工具,自动迁移了差不多有100多个项目,线上零Case。

    0e492220919edcdbecd4353be4033018.png

    另一个是做框架生态的大版本升级,假如一个季度推出来一个大版本,实际业务开发升级难度、成本就会比较大,业务可能也不敢升级,这时大版本升级就要提供关键流程自动迁移支持:

    1. 当从Yarn到Pnpm的时候,会做幽灵依赖检测,自动向Pnpm/src的幽灵依赖配置等;

    2. 也会做工程源码对比;

    3. 构建配置,如Webpack前后框架无关的配置对比;

    4. 产物变动升级前后entry数量是否不一样、产物有没有明显变大;

    5. 兼容性检测,升级前是ES 5+的代码,升级后到ES 6了,那也会出问题;

    6. 线上验证等。

    4cf700a6f261e3b2b27a62a3b4651663.png

    公司内部的一些标杆团队都是由我们Rome团队升级+写报告,标杆业务由基建团队升级的话,ROI可能会比较高,我们升级通过工具将我们的二次调整,整体成本可能会非常低,2~4h就可以完成一个中等存量项目,再由核心业务同学验收、线上灰度跟进等。

    3 框架开发辅助

    我们Rome的工程开发辅助工具是基于IDE的。一般业界的开发辅助工具两种形式,下图是Vue UI和VSCode的拓展图示:

    | 3.1 为什么要基于IDE?

    e4341b66e4776e6a212424574dea2412.png

    理解:对于Web形式,业界以Umi UI(更先进)和Vue CLI为主,虽然它们都是基于Web实现,但出发点不太一样,Vue UI核心是做体验提升,支持工程创建CLI可视化,工程配置分析等;但是UMI UI要服务公司内部,更多的是做提效,支持一些组的资产插入、执行工程任务比如build/lint等。

    基于Web做开发辅助工具

    c225c34c71559741bca7f62dd28e3cb0.png

    IDE侧方案确实存在UI交互受限、视窗面积、跨IDE开发成本等问题,因为同学在开发时,VSCode的面积就这么大,每弹出一个Webview就会侵占用户的开发视窗,会比较难受。

    选型原因:

    4b447499b334059a69cfcbc1b16bfbaa.png

    | 3.2 提效率

    提效率的一个例子是“一分钟内部署”,这里主要解决我们高频的测试环境部署流程冗长问题。2021年我们Rome⾮线上环境发布⼤概10W次/年,核⼼流程369s/次,如下图所示:

    a109f7f49090a0ed6339b22ede519146.png

    通过我们的开发辅助工具,可以做到页面粒度的CSR/SSR发布,同学不需要关注跨平台之间有哪些工作量,我们会在背后同步并且流转DevOps节点,把原本我们要在研发流程中,企业内要做质量分析、规范卡控等部分做异步,然后异步进行触发,整体的链路就可以保证一分钟内完成部署。

    | 3.3 提质量

    IDE可以做开发时质量检测,开发时会有历史的线上故障提醒。

    哪些问题我们之前已经出过很多次线上故障了,在开发时就会实时检测代码并提示这部分应该进行修复,否则后续可能会出现线上故障。

    它和ESLint的区别:

    1. 首先是我们可以做规则的动态下发,研发规则配置,做管理中心化;

    2. 内容上我们也会支持故障包版本,比如业界之前出过几次故障包问题,包括core-js、内部组件库故障版本等;

    3. 我们也会把历史业务线上故障分析出来并提示,点击链接就可以跳转详细查看之前具体是出了哪次线上问题,是由什么引起的。

    ce347428d85026783be703b8612cc5cf.png

    | 3.4 平台流转

    我们内部研发时不仅要开发,还有设计稿,包括DevOps平台的流转等,也会上下游联动,保证设计可以快速到DevOps平台,DevOps平台可以一键打开本地VS Code,记忆历史的仓库和分支并快速打开,也可以快速流转到设计平台,开发完返回剩余流程。

    2efbedcc1f6f558cb2b34b58d1b19b22.png

    | 3.5 文档提示

    开发时也会给到大家文档提示,只要研发人员托管到到店内部的知识库,就可以在开发时,自动进行相关文档的匹配和跳转提示。

    56c8f001a448bb539fa5a4d12a96fdc7.png

    | 3.6 CloudIDE对接

    得益于业界IDE标准的高度统一,一般CloudIDE仅需一次开发,即可本地、云端IDE自动安装开发辅助,能力完全一致。

    2f630641a478ea91159121a1faaf3559.png

    4 框架度量和业务实践

    上文中从接入公司基建、编译提速、框架大版本升级等方面提到了很多工程能力,过程中也建设了升级、迁移工具,而作为企业内框架,也有一些问题和指标需要考虑。

    | 4.1 框架度量-核心问题

    问题和指标

    38349dddc21e11cfd0618cf903796402.png

    在业务规模不断扩大、能力落地覆盖范围及用户数量都在不断增加的背景下,框架现状衡量、框架如何发展等问题逐渐显现:

    Rome的用户群体从纯B端业务到覆盖B&C端业务,业务节点已覆盖4个事业群、15个事业部;对比2020年,项目规模已经扩大了11倍,公司内共落地1000+项目。

    1. 如何判定标杆业务、框架能力支撑效果,如何持续快速统计用户规模并做运营?

    框架价值=覆盖范围 * 功能价值。能力开发完我们需要尽可能清晰化并提升落地覆盖,在统计运营上可以通过CI/CD平台发布过程数据、Git仓库扫描数据、框架运行时数据打点、IDE使用数据来做框架能力和用户规模数据采集;同时结合标杆团队、标杆业务以组织维度框架生态能力最大提效数据,并对能力验证和优化有正反馈,促进能力高质量、更大规模落地。

    2. 哪些生态能力使用频率高,哪些能力使用频率低,哪些是安装在项目中但没有实际使用的?

    面对已建设的生态能力,如果纯从能力开发视角出发、缺少有效的衡量体系,会导致有限的人力会被分摊到非常庞大的工程体系内:(1)已有的好能力因为没有度量数据,感知弱,在人员变动等客观背景下没有得到持续足够的推广导致好能力没有获得足够的落地,导致收益低于预期。(2)初期能力建设完后产生持续的维护成本,对部分使用率低的能力无法感知,未及时做出关键判断,产生一部分人力浪费。(3)对存在优化空间的能力,由于未及时拿到使用数据,不了解落地问题,能力未得到持续验证和优化而导致收益不达预期。

    3. 框架如何从产品角度量化价值?

    从人力节省、质量、缩短交付周期等方面建立有效的产品价值衡量体系,对齐框架年度输出指标并持续运营。

    4. 下个阶段框架发展方向和重点是什么?

    不变的是要深入结合业务架构重点支撑阶段核心业务场景,紧跟社区做一些先进能力,同时需要通过数据来辅助判断阶段重心是提升框架核心能力覆盖率,还是要建设新能力。

    5. 框架面向用户群体的客服成本是多少?如何降低?

    收集客服数据,沉淀高质量的FAQ,保证增量问题不被重复客服,引入AIGC智能客服等方式降低增量能力客服成本。

    | 4.2 框架度量-全景建设

    解决思路

    统一定义并梳理指标来源,结合上下游平台提取数据、对缺失数据采集并持久化,通过快照等形式完成数据层聚合和差异抹平;中间层会按照定义的大盘指标对数据进行统计拟合校准,包括项目覆盖率、核心能力使用率、接入率、研发环节效率等等;上层会按不同的业务部门、时间区段等提供可切换的覆盖、效能、质量等数据看板。

    879e81515918fcc68d23acd8c04a94d7.png

    数据来源层:

    数据统计层:

    大盘指标层:

    交付(各模块的数据看板):

    运营模块:

    | 4.3 业务实践

    整体Rome业务实践如下图所示:截止2022年,落地了1400多个工程项目,资产库的数量有100多个,到店多数Web项目是用Rome开发,大家打开美团App,可以看到到店业务H5页面都是通过Rome进行开发的,有B端系统、C端的H5,还有我们美团内部的React Native。

    f9c0a815ab393ff3db12aae7731a6c23.png

    5 总结及工程框架趋势思考

    工程框架不止于CLI。要从需求交付的视角做框架,整个工程链路可能涉及到应用创建、应用认证、开发基建配置、依赖安装、编码、Mock、调试,包括提交Lint、还有Git、Install、Int、Build、Upload、灰度、Publish等等。

    我们要核心关注高频的、规模化、价值比较高的环节:

    1. 依赖安装环节,因为本地开发和线上部署都会使用到,如果这部分是当前核心的耗时点(发布总300s,依赖安装100s),下个阶段构建就可以先放一放,把依赖环节的优化提上日程;

    2. 开发编译环节,很多时候开发环节我们提升了50秒,看起来好像没有那么高,但我们团队如果是1000人有几千个项目,调试编译频次是很高的,全量落地后规模化效果就会非常强;

    3. 发布链路层面:交付链路中涉及整个研发的全部上下游,单纯做单点的工程优化(如本地构建优化)效果不一定好,可能到后来只是在卷几秒的差异。部署阶段依赖、构建缓存复用可能可以直接降低 10min/次;另外部署时流水线节点异步触发、测试环境聚焦提速快速看到效果,线上再补充管理所需的质量分析、卡控等

    4. 链路流转环节:工程框架和上游的设计协作平台怎么流转、下游如何和部署平台联动,他们的耗时可能也比较高,这部分也需要关注,因为对使用我们这套工具的同学来说,不关注这个能力是谁提供,而是我们在开发需求的时候,他明显会感觉到你们整体提供的这套产品,我用起来很难受,可能不一定是工程框架部分,单体都不错,一起用就是不够顺滑。

    690c3f475d37d2771463c6d3432e6772.png

    未来趋势(个人阶段视角):

    1. 第一方面是工程框架要做开发链路的深度整合,可以类比业界的Vercel,我们企业内也可以类比这些成熟的像SaaS产品去做;

    2. 第二方面是此前提到的Rust基建、构建切换Rspack/Vite、辅助开发工具,保证生态完善,公司内可以平滑升级;

    3. AI时代:编码Copilot;如何结合公司内AI基建把历史业务模板、组件库、资产库做提示生成是一个可以结合的点(框架有相对严格的资产生产结构规范,可以提升下游编码时资产消费准确率);通过知识库问答降低技术项目的客服成本等。

    ----------  END  ----------

     推荐阅读 

      | 美团外卖终端容器无关化研发框架

      | 美团 iOS 端开源框架 Graver 在动态化上的探索与实践

      | 美团开源Graver框架:用“雕刻”诠释iOS端UI界面的高效渲染


    标签:

    上一篇: AngularOrg - Api 下一篇:
    素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。