作者:katecjzheng腾讯PCG前端工程师
背景
我们在研发的是一个toB的低代码平台。简单来说,就是利用可视化的方式,通过拖拽组件到画布中,结合数据源的绑定,用来生成管理台的工具。
实际上,管理台的模式相对固定,有大量同质化需求,套用低代码去实现最为合适。对于画布来说,组成UI的组件库就最为关键。目前我们提供了40个官方公共组件,能满足大部分管理台需求。
但业务方一定有定制化组件需求。而只要自定义组件的生产门槛有一点高,就会劝退使用方,甚至直接不使用整个平台。最理想的模式应该是,整个画布大块(甚至全部)的区域,能直接使用公共组件拖拽生成;而其中一些块,能够用自定义组件进行填充。既能完整地还原页面需求,又能减少重复开发工作(主要指平台的公共组件、接口调用、平台权限等),最大化获得使用低代码平台带来的收益。
而对于一个自定义组件,必须足够灵活。组件开发者可以选择将组件共享出来,供其他团队搭建管理台时直接使用。或者作为一个原子,供其他自定义组件套娃依赖使用。并且,组件最好跟项目相互独立,这样任意一个组件可支持跨项目进行复用。
1.组件开发流程
目标:对齐原生组件开发体验,所见即所得。指的是,不需要发布组件后,才能看到组件在多个远程管理台多种场景的呈现效果。当然了,也不能出现太多"个性化"概念让开发者去理解(比如如何引用自定义组件,自定义属性面板等)。
2.组件依赖管理
管理台中涉及大量组件包含组件的场景,所以会聊到组件在线上的版本策略问题。
平台级组件开发方式
1.组件的基本构成
一个完整的组件,由组件本身的UI,以及属性面板构成。调试时两者需要联动,需要在组件UI上,实时看到对应的属性配置效果。
属性面板一般涉及到数据源、管理台页面等的绑定,需要跟平台功能互通。如考虑最最传统的组件开发模式:不提供宿主环境,直接开发一个组件,发布到平台使用。
总结:组件脱离平台进行开发,需要反复发布、线上验证才能达到预期效果。
2.传统的组件开发模式-进阶版
那让用户直接使用平台代码进行开发,这样就有宿主环境了。
第一步,拉取平台代码
第二步,偷偷问平台管理员拿账号密码(平台级账号密码是保密的,不在代码中)
第三步,一翻折腾后把整个平台代码跑起来,终于想起来是为了开发一个小组件(这才是关键啊喂)...
换个思路,只base拖拽生成的管理台代码进行开发,在我们无极平台上也无法成立。主要因为平台的页面产物是数据配置(布局格式是一种类似jsonSchema的协议),没有代码,更无法在这个基础上进行组件开发。
3.平台级组件开发模式
既然要搭建一个一模一样的平台进行开发如此困难,我们能不能直接使用远程管理台进行开发呢?无极实现的组件开发流程分为以下几步:
远程管理台分为生产模式和开发模式。CLI工具会收集本地仓库的组件开发列表,提供接口给远程管理台拉取。开发模式下,组件的加载策略是,本地组件优先从localhost加载;远程组件则直接从组件的cdn地址加载。这样就实现了本地自定义组件与线上组件在线上布局中混排。
刚谈到远程管理台加载了本地组件JS,实际上,这个本地组件JS会注入websocket客户端和HMR更新模块的代码,当本地代码发生变更,本地CLI的websocket会与远程管理台通信。HMR模块会请求最新的组件JS,并控制DOM节点的更新(无极参考了开源仓库webpack-hot-client的思想进行了改造,大致思路两者基本对齐)。
我们来演示一下最终HMR达到的效果:
这样,可以在多个线上管理台上,实时看到组件修改后的效果。并且跟原生的vue组件开发方式,毫无差异。
3.组件批量开发
方案灰度使用时,当单个仓库10+个组件同时开发时,启动命令首次构建时,在单进程中暴露出性能问题。于是我们的思路是改单进程的串行为多进行的并行执行,每个组件独立子进程进行构建,达到最小化耗时。并且由主进程进行socket连接的分发,最终只占用了一个端口。此时构建中间件主要由以下几步构成:
1、worker进程池,一个子进程维护一个组件的构建服务
2、master进程,维护组件信息池以及socketserver池
3、由master进程,统一对远程管理台页面进行消息通信
我们来看看最终的优化效果:
小结,无极目前的组件开发模式,通过复用真实的管理台,最大程度地降低了组件开发的成本。我们相信只有提高开发效率,才能让组件开发者更好地参与到组件生态的共建中,从中孵化出高质量组件。
组件依赖管理
1.背景
无极是toB的,涉及到大量组件包含组件的场景,例如列表组件和复杂表单组件(一个复杂表单组件会包含输入框、图片、按钮等)。对于无极平台,组件依赖以及组件的线上版本策略,是很重要的一环。
2.组件的构建方式-锁版本pk不锁版本
举一个例子来表述问题吧。假设组件A依赖文本输入框组件。
一般会有两种构建方式:
一种是bundle的打包方式,就是锁版本。也就是说,将输入框组件打包进组件A中。
这个方案最大的优点是组件是自治的,输入框组件的版本维护由组件A自行处理,没有组件升级的风险。缺点是管理台中如果也使用了文本输入框,就会存在两个文本输入框版本,可能会导致样式不一致等问题。并且,会增加组件的JS打包体积(例如,柱形图和饼图,都依赖了echarts组件,把echarts组件各自打包进两个组件中,是不是有点可怕?)。
实际上,bundle方式在toC场景中使用最多,它的稳定性最好。toC的h5组件一般相互独立,不涉及复杂依赖链,只求稳定。这时,公共库的版本是锁定的,通常是需求需要新功能或者有bug时,开发者才会手动进行某个组件的版本升级。
而无极作为一个toB平台,有大量组件复杂依赖的场景,比较适合动态依赖的方式。平台不可能逐个通知多个业务方,去进行升级,并且旧版本组件不可能进行持续维护,大量组件逐个升级十分麻烦。于是我们选择动态依赖的方式,直接把线上运行时版本去掉了,也就是线上只有一个唯一版本,就像小程序一样。
而对于全局升级带来的风险,目前只有官方组件有大范围依赖,这个风险可以由官方团队用一些工程化的手段,例如单测、灰度(后面会提及)等,去保证向下兼容。
3.如何实现组件动态依赖?
我们不希望无极组件的依赖方式过于个性化,所以首先考虑对齐日常组件的引用模式。最后拍板使用@wuji域作为公共依赖的标记,构建时会分析代码中的@wuji域的加载,并改造构建产物。
整个构建流程分为以下几步:
1、提取@wuji域的加载模块,收集依赖
2、将依赖列表注入到全局组件加载器的注册函数中。加载组件JS时,会先异步拉取依赖列表中的组件JS,将组件对象放在内存中
3、@wuji域的加载,会替换成全局组件加载器加载函数。组件加载器的require方法会从内存中获取组件对象,接下来进行组件的实例化
4.组件配套的多环境
目前平台为每个组件提供了测试环境、灰度环境(开发中)、生产环境。各个环境是这样设计的:
1、测试环境。私有部署可以单独部署一套服务,将全部组件指向测试环境,进行统一的预发布验证
2、灰度环境。以项目为粒度,可以配置某个项目使用某个组件的灰度版本,待验证后,再由开发者将灰度版本转为正式版本
3、生产环境。线上使用的唯一版本。每个组件都有维护自己的版本列表,可快速回滚至任意版本。
通过多环境进行验证,可以有效提高组件全局升级的可控度。
组件生态的共建
无极是一个平台,会有多个业务的私有部署。公共组件统一由官方源进行组件信息的存储,而设计组件存储的时候,我们会将私有部署理解成一个源,一个源里面会有多个自定义组件,自定义组件会由自己的组别进行分类。
最后
总结一下无极低平台的组件方案,目前做到以下几点:
1、通过复用真实宿主环境开发,简化开发调试流程
2、组件托管,快捷一键发布到线上开发环境
3、配套的多环境验证
4、运行时自动依赖分析,组件全局唯一版本,减少版本对组件开发者带来的复杂度
希望能通过这些细点,让整个开发流程、使用流程更爽,打造一个围绕组件的良性生态圈。对于整个低代码平台来说,也是后续可持续运营和有足够扩展性的基础保障。