SREWorks前端低代码组件生态演进:monorepo架构重构和远程组件加载实践

news2024/11/18 17:27:37

作者:王威(地谦)

文章结构

  • 项目背景
  • 演进分析
  • monorepo架构演进
    • Webpack与Rollup
    • 如何平滑迁移
    • 构建优化
  • 组件的可扩展与可插拔
  • 演进总结
  • 版本动态

项目背景

SREWorks是一个面向企业级复杂业务的开源云原生数智运维平台,是大数据SRE团队多年工程实践的锤炼及沉淀。前端统一托管工程(frontend)作为平台的重要一环,提供了一套serverless体验的配置化前端低代码技术方案:低代码、配置化是前端低代码方案的基础特性。

frontend工程采用React+antd为主的技术框架,设计了一套组件映射、编排、解析、渲染的工程体系:以antd组件为自由编辑粒度,用户在前端设计器通过可视化交互或者json编辑的方式,依据运维工作的实际使用场景,对组件进行属性配置/组件嵌套拼装;同时根据使用景目标需求对页面组件进行布局的编排、数据源的绑定以及在合适点位插入Dynamic Logic,完成页面节点的设计工作,形成节点模型nodeModel,经模板解析引擎进行解析渲染。由于之前已对架构设计做过一篇详细的介绍,在此不再赘述,详情可移步这一篇 https://mp.weixin.qq.com/s/_kqItPbivVmIrOVXvEaVlg

image.png

我们开源这套前端工程的愿景是:沉淀更多的使用场景,整合更多的用户需求,与社区一起共建一个丰富的前端运维组件生态。在过去的半年中,为了让前端组件生态更好地演进,frontend 针对 “可扩展、方便插拔”这两个关键点进行架构升级:

  1. 架构层面进行了monorepo模式重构;
  2. 前端组件支持远程动态加载;

在文本中,我们对整个迭代过程中陆陆续续碰到过一些问题,以及技术方案的选择与思考做一个阶段性的归纳和总结。

演进分析

关注我们开源动态的同学应该知道,我们初版开源的frontend代码量近10万之多,在没有可靠详实文档的帮助之下,想要快速理清楚整套工程的设计理念,结构机理进而能参与贡献还是有一定难度的。同时工程内部细分来看,设计器,模型层,组件层各自又有相差很大的更新频率,在开发时一个小小的改动都需要整个工程进行构建。

另外一方面,frontend来源于公司内部工程实践的版本,两者虽然同源,但是由于公司内部和开源场景都在快速功能演进,最初设计的公共框架层和组件层共享机制已经有些举步维艰,这也为后续这次演进迭代埋下了伏笔。结合我们打造开源生态“可扩展、方便插拔”两大目标,综合来看需要解决以下问题:

  • 基座层面支持runtime远程组件的加载,解决用户的多样化的场景与诉求
  • 结构上对大而全的工程进行细粒度拆分
  • 提取framework框架层和widget组件层并能够单独构建
  • share-tools工具可共享
  • 内部业务代码剥离
  • 在适配内部业务运转的前提下升级各依赖版本,便于新技术引入与演进
  • 构建工具的升级与配置调优,有效提升构建效率降低构建体积

针对以上待解决的问题,对演进方案进行了技术调研,也参考和采纳了社区同学的建议,我们决定采取下面两个方案来解决上文提到的问题:

  1. 架构层面,采用monorepo模式进行重构提取出framework框架层、widget组件层、shared-tools等几个子依赖包,以webpack5(主应用包)+rollup(子依赖包)作为构建工具进行过调优构建;
  2. 针对无法进入代码库的组件,提供远程组件脚手架,支持将远程组件打包umd格式并以动态script标签形式进行动态引入和移除,做到runtime加载扩展;

下面我们来详细分享下这两项方案的实施:

Monorepo架构演进

Monorepo即单仓(repository)多包(package),大型前端工程项目采用这种模式进行开发管理,能带来诸多的开发和管理便利:

  • 更加清晰的模块结构和依赖关系
  • 更细粒度的独立构建单元便于协作开发和不同更新频率的子包单独发版
  • 更加高效的代码复用等

在v1.4版本中采用lerna + yarn workspace 的技术方案进行了Monorepo的架构实践:将原工程拆分为@sreworks/app主包应用,和@sreworks/components、@sreworks/widgets、@sreworks/framework、@sreworks/shared-utils四个npm子依赖包。目录结构变动如下图所示:

image.png

通过lerna+yarnworkspace的方案,将各子包配置进入workspace空间,workspace空间的各子依赖包的更新,会实时同步到主应用包的node_module,无需发布npm,且能选择针对特定子包单独发布npm版本或者各个包同步发布新的版本,可以更小粒度的更新主应用依赖,便捷高效。

Webpack与Rollup

在设计好子包的拆分之后,就开始着手进行文件结构的改造、组件引入挂载方式的变更、远程组件加载的处理优化,主题式样的迁移等等问题(由于篇幅有限,本文仅对大的通用环节进行介绍,对处理细节感兴趣或者想讨论沟通的同学可以加入文末的交流群)。

在处理完工程结构代码后,我们开始着手工程的构建:构建工具的选择,关于构建工具,webpack,gulp,rollup以及后来的vite,综合我们实际的情况,最后选定了Webpack和Rollup作为备选方案:Webpack和Rollup本质都是对非ES5代码的转义与打包,一个功能强大的compiler函数,通过配置入口读取目标文件,然后输出转义文件;要完成整个工程的打包,还需要babel-loader,React和Vue等loader的处理和一系列plugin的适时挂载处理才能完成对诸如图片,css文件、JSX及Vue template等类型文件的处理,及js挂载html的工作。

Webpack与Rollup的特点:

image.png

根据以上特点对比以及参考业内优秀开源项目实践,frontend选择了主包应用使用Webpack5作为构建工具,Rollup作为子包应用构建工具的方案,主包应用HMR对于日常开发而言是刚需,因此选择Webapck;对子包依赖而言,更便捷的配置和更小的输出才是更佳的选择。

image.png

image.png

如何平滑迁移

整个这么大的工程体量,在没有完全进行代码层面准确无误的拆解并构建的情况下,是跑不起来的,一个很小的错误都会造成整个项目抛错。且二方包使用了sourcemap也是没有用的,经过了主包构建,很难排查出哪里除了问题,于是就又要推倒重来……在开始的实时过程中,耗费了很多的时间,叠加每个子包的修改排查,主应用包的构建等验证周期很长,探索性改造的难点就在于此。

那么能更小粒度的验证和迁移吗?远程组件的加载给了启发思路。尝试性将组件包@SREWorks/widgets打包成esm格式并在原来大而全的工程中直接修改node_modlues引入依赖包打包文件, 和相应加载机制,在能运行起来的工程上去验证各子依赖包,配合sourcemap, 问题排查瞬间提速。就这样,又依次进行@SREWorks/framework等其他包的验证,蒙眼构建排查问题得解。

式样问题比较头疼,在此采用的方案是通用式样在主包保留,子包由于式样重置覆盖的场景较少,采用了css-module的方式进行隔离构建。

构建优化

经过各子依赖包在原有工程上进行平滑验证,来到主应用包的构建环节,构建体积竟然达到了惊人的5.5M,还是gzip压缩后的体积:

image.png

通过分析这张图,该版本构建存在以下问题:

  • 同名依赖多次出现,各子依赖包存在重复的依赖
  • 部分依赖包构建体积偏大,如BizCharts

针对以上存在的问题对@sreworks/app整体进行三个维度的优化处理:

第一,通过统一子包依赖排查合并依赖版本,优化至2.8M

image.png

const namespace = {
  appRoot: path.resolve('src'),
  appAssets: path.resolve('src/assets'),
  // 减少子依赖包内部重复依赖
  '@ant-design': path.resolve(process.cwd(), 'node_modules', '@ant-design'),
  'js-yaml': path.resolve(process.cwd(), 'node_modules', 'js-yaml'),
  'ace-builds': path.resolve(process.cwd(), 'node_modules', 'ace-builds'),
  'brace': path.resolve(process.cwd(), 'node_modules', 'brace'),
  'lodash': path.resolve(process.cwd(), 'node_modules', 'lodash')
}
...
  resolve: {
    alias: paths.namespace,
    modules: ['node_modules'],
    extensions: ['.json', '.js', '.jsx', '.less', 'scss'],
  },

第二,抽离部分大依赖包到cdn,如下在externals配置项进行剥离;将体积优化至1.6M。但考虑到某些专有云使用场景,无法使用外部cdn。于是采用自定义构建脚本,从node_modules中迁移目标依赖到输出文件夹并加载至html的方案,降低参与构建的大依赖包数量,同时保证专有云环境对其正常的使用。

  externals: {
    // 剥离部分依赖,不参与打包
    'react': 'React',
    'react-dom': 'ReactDOM',
    "antd":"antd",
    ...
  },

第三,调整关键组件路径和1.48M, 减少体积70%,构建时间由V1.3版本的74秒,优化至23秒,提升68%。

image.png

组件的可扩展与可插拔

虽然frontend已内置运维场景常用的基础组件,图表组件,landing组件,布局组件等五十余个组件。根据开源之后用户的使用反馈来看,用户仍然有着定制化,可扩展的共性诉求:总的来讲大致分为两大类:

  1. 前端框架也是React,有自己定制化的使用场景,内置组件不能满足当前需求,需要扩展
  2. 前端技术栈是Vue,历史组件积淀比较多,全部进行React重构成本太大

针对问题一,frontend本来就有提供JSXRender,支持用户以JSX进行简单的静态渲染类的组件自定义扩展,但不支持属性配置以及数据源及dynamic业务逻辑处理等高级特性。前端插件化,很容易想到npm包的引入,但是这也只能在工程代码开发的场景下才适配,要runtime使用和移除,就要另寻方案。再进一步深入追溯,前端开发从jQuery时代发展到当今的Agular,React,Vue三驾马车以及各种工程化构建工具的参与,但本质其实并没有发变化,依然是以html中以script标签挂载js代码进行渲染加载的。因此自然想到以script标签的形式加载我们的远程组件,不过这里要做到动态、批量加载、可移除,即:将远程组件打包umd格式并发布到云端,并获取相应准确路径,以动态script标签的形式引入:

(function (){
  let script = document.createElement('script')
  script.type = 'text/javascript'
  script.src = url // 目标组件url
  document.getElementById('targetDomId').appendChild(script)
})()
script.addEventListener('load',callback,false) // 嵌入逻辑

如果要批量加载多个的话,即:

const loadRemoteComp = async () => {
  let remoteCompList = ["url_a","url_b","url_c",...];
  try {
    remoteComList.forEach(item => {
      pros.push(Promise.resolve(loadSingleComp());
    })
    window['REMOTE_COMP_LIST'] = await Promise.all(pros);
  } catch (error) {
    console.log(error);
  }
}
loadRemoteComp()

当然这里还涉及到浏览器终端适配,容错等细节。在此frontend采用比较成熟的systemjs包进行组件的加载,对以上细节都有做妥善处理,合理借力,省时高效。

针对问题二, 技术栈不同,即异构组件的加载。目前来说frontend暂且只针对Vue组件做了异构兼容渲染,在React中使用Vue组件。一开始想到的是使用转换工具,将vue组件手动转换为React组件,之后再粘贴构建,但这种方式有个很大的缺陷:不同版本api差异较大,手动转码一般需要对转换过后的代码进行人工二次排查调整,需要开发人员对于两种框架的新老版本属性熟悉了解,对于不符合的代码或已更新的hooks等进行二次确认,无形中提高了使用门槛。

受到Docker容器的启发,思考React和Vue虽然属于不同的技术栈体系,但区别于Java和Golang的差异,Vue和React在本质上都是原生js对象的封装,所以理论上讲是可以在React中进行容器化渲染Vue组件的:即本质是绑定挂载Vue对象的操作:

createVueInstance (targetElement, reactThisBinding) {
  const { component, on, ...props } = reactThisBinding.props
  reactThisBinding.vueInstance = new Vue({
    el: targetElement,
    data: props,
    ...config.vueInstanceOptions,
    render (createElement) {
      return createElement(
        VUE_COMPONENT_NAME,
        {
          props: this.$data,
          on,
        },
        [wrapReactChildren(createElement, this.children)]
      )
    },
    components: {
      [VUE_COMPONENT_NAME]: component,
      'vuera-internal-react-wrapper': ReactWrapper,
    },
  })
}

通过frontend远程组件脚手架@sreworks/widget-cli,对React组件和Vue组件进行打包并发布到cdn,然后在物料开发处,进行编辑即可便捷进行远程组件runtime加载和移除,解决了问题一和问题二,达成了“扩展性”和“可插拔”的目标。

演进总结

到这里,基本解决了开篇列举的一系列问题,为构建前端运维组件生态铺设好了共建路径,可以做到:

  • 从@sreworks/widgets包开发,JSXRender自定义组件,使用@sreworks/widget-cli开发远程组件三个维度扩展组件应用丰富度
  • 更加清晰的结构依赖关系,降低学习和贡献参与这套低代码工程的门槛
  • 以更小粒度的更新单元,更短的构建时间,便捷日常协作开发
  • 子包拆分后,为后续小规模分步引入TS提供了条件

版本动态

我们会根据工作项目节奏,持续对功能进行完善优化和升级,当前主要是前端低代码功能的输出,后续API低代码编辑编排已纳入版本规划,以覆盖全链路低代码使用,大家有比较好的建议欢迎多提issue,同时也欢迎更多的开发者能够参与到我们的生态建设中来(@小助手,也可以直接前端@地谦)

SREWorks开源地址:

https://github.com/alibaba/sreworks/paas/frontend

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wafw00f 防火墙探测

kali机器自带防火墙探测工具wafw00,它可以通过发送正常以及不正常甚至包含恶意代码的HTTP请求,来探测网站是否存在防火墙,并识别防火墙的厂商及类型。安装:git clone https://github.com/EnableSecurity/wafw00f.git python setup…

Windows下载安装Prometheus

目录 资料 下载 解压 点击prometheus.exe运行 资料 Prometheus是一个开源的系统监控和报警系统,同时也支持多种exporter采集数据,还支持pushgateway进行数据上报,Prometheus性能足够支撑上万台规模的集群。 官网:https://pr…

DSIN模型

DSIN模型提出得动机:用户得行为是由会话组成得,在每个会话内部用户得行为是相似得,会话之间得用户的行为是存在较大差异性得,而其他模型都没有关注这点,所以就有了DSIN模型。 在这里我们来讲下DSIN关键得四层&#xf…

PR9268/300-000库存现货振动传感器 雄霸工控

PR9268/300-000库存现货振动传感器 雄霸工控PR9268/300-000库存现货振动传感器 雄霸工控SDM010PR9670/110-100PR9670/010-100PR9670/003-000PR9670/002-000PR9670/001-000PR9670/000-000PR9600/014-000PR9600/011-000PR9376/010-021PR9376/010-011PR9376/010-011PR9376/010-001…

2023年最新qq空间说说怎么全部删除_QQ空间说说如何批量删除

2023年最新QQ空间自动删除说说_2023批量删除QQ空间说说插件小工具_QQ空间如何一次性批量删除说说 一千多条说说怎么删?QQ空间说怎么批量删除_怎样把发的空间说说全删了 使用谷歌浏览器插件,一键安装之后,就可以实现「自动删除」和「手动批量…

SQL入门DEMO

单表查询 ● --查询订购日期在1996年7月1日至1996年7月15日之间的订单的订购日期、订单ID、客户ID和雇员ID等字段的值 ● --查询供应商的ID、公司名称、地区、城市和电话字段的值。条件是“地区等于华北”并且“联系人头衔等于销售代表”。 –查询供应商的ID、公司名称、地…

如何将Google浏览器安装到D盘(内含教学视频)

如何将Google浏览器安装到D盘(内含教学视频) 教学视频下载链接地址:https://download.csdn.net/download/weixin_46411355/87503968 目录如何将Google浏览器安装到D盘(内含教学视频)教学视频下载链接地址:…

正态性检验全流程

正态性检验处理流程 一、分析问题 在实际研究中,正态性是很多研究方法在进行分析时需要满足的前提条件。常见的比如方差分析、T检验、相关分析、回归分析等等,这些分析方法使用的前提假定就是需要数据满足正态分布。 但是这一点经常被分析人员有意或无…

潜伏的 Linux Rootkit:Syslogk

Rootkit 是非常危险的恶意软件,一旦侵入就很难被发现。开发 Rootkit 通常更加困难,很多攻击者都倾向于重用开源项目。 Adore-Ng 是一个相对较老的、开源的 Linux 内核 Rootkit,最初针对内核 2.x 版本开发,但目前已更新为针对内核…

【黑马JVM(1)】内存结构

JVMJVM/JRE/JDK示例JVM内存管理JVM整体架构程序计数器虚拟机栈栈内存溢出线程诊断 top/ps -H/jstack案例一:CPU占用过多案例二: 程序运行很长时间没结果本地方法栈堆堆内存溢出堆内存诊断案例一:jps/jmap/jconsole工具使用案例二:…

Java---打家劫舍ⅠⅡ

目录 打家劫舍Ⅰ 题目分析 代码一 代码二 打家劫舍Ⅱ 打家劫舍Ⅰ 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被…

设备树实践操作

目录一、使用设备树给DM9000网卡_触摸屏指定中断1、修改方法2、实验方法二、在设备树中时钟的简单使用1、参考文档2、知识讲解三、在设备树中pinctrl的简单使用1、几个概念2、设备树中pinctrl节点3、platform_device, platform_driver匹配4、驱动中想选择、设置某个状态的引脚四…

ESP32设备驱动-BMI160惯性测量传感器驱动

BMI160惯性测量传感器驱动 BMI160 是一种高度集成的低功耗惯性测量单元 (IMU),可提供精确的加速度和角速率(陀螺仪)测量。 BMI160 集成: 16位数字,三轴加速度计16位数字,三轴陀螺仪BMI160特性: 高性能加速度计和陀螺仪(硬件同步) 极低功耗:typ.925A(加速度计和陀螺…

BIM小技巧丨关于如何在Revit明细表中显示门窗面积

在明细表中显示门窗面积(以门明细表为例)在新建一个门明细表后,可以发现在Revit中不能直接使用明细表统计门窗面积。 这时,可以通过使用添加“计算值”的方式来处理,得到如下图所示,两种不同的面积统计结果: 除此之外&…

Android 12 快速适配

Android 12 需要更新适配点并不多,本篇主要介绍最常见的两个需要适配的点:android:exported[1] 和 SplashScreen[2] 。一、android:exported它主要是设置 Activity 是否可由其他应用的组件启动, “true” 则表示可以,而“false”表…

满汉楼练习 马踏棋盘

1. 满汉楼 1.结构图 2. 数据库 pwd CHAR(32) NOT NULL DEFAULT ‘’,# 密码,32位 INSERT INTO employee VALUES(NULL, ‘666’, MD5(‘123456’), ‘老韩’, ‘经理’); MD5(‘123456’)是经过MD5加密过后的32位的字符串,用来保存密码 select * fro…

辉光管时钟学习制作及开源软硬件工程

文章目录前言开源地址辉光管项目介绍辉光管的工作条件硬件部分部分介绍充电电路驱动电路不足之处软件部分总结前言 作为一个电子人,一直想做一个辉光管时钟,算是大学的一个心愿,终于在快要毕业前做了一个,下面把软件和硬件的部分…

Windows事件日志监控

大多数数据泄露属内部人员而为,但各企业在监控内部网络活动方面仍存在不足。无论是大型还是小型企业,监控内部网络活动已成为其主要要求。要保护网络安全以防范泄露和威胁,各企业需要采取积极的措施来保证其网络和数据的安全性。监控事件日志…

NCRE计算机等级考试Python真题(四)

第四套试题1、以下选项中,不属于需求分析阶段的任务是:A.需求规格说明书评审B.确定软件系统的性能需求C.确定软件系统的功能需求D.制定软件集成测试计划正确答案: D2、关于数据流图(DFD)的描述,以下选项中正…

跨境人都在用的指纹浏览器到底有什么魔力?三分钟带你了解透彻

什么是指纹浏览器?这是东哥近期收到最多的粉丝私信咨询,指纹两个字大家都很熟悉,指纹浏览器就变得陌生起来。之前东哥也跟大家分享过很多次指纹浏览器的用法,鉴于还是很多人不认识这个好用的工具,东哥今天就来详细给大…