本章节主要是物料组件的开发设计,之前提到了物料的结构与构成,但是并没有做明确的解释。作为低代码编辑器中核心的模块之一。
物料即承担了一个提供者的角色,通过对编辑器注入物料组件来完成页面的渲染和可视化编辑器的编排,最终产生出理想的 Schema 协议。
同时也是消费端的组成之一,渲染器需要在解析 Schema 后将对应的物料渲染到页面,完成低代码的可视化产物。
所以本章将介绍组件与物料的一些必要的设计。
什么是物料?
不仅仅是在低代码平台中,日常开发当中抽离出来的业务组件、逻辑区块、模版等也可以称之为物料,低代码物料与其不同则在于多了一层属性设置器。
它的结构是一个包含关系,如下图所示:
低代码中使用到的物料在编辑器中填充需要额外给定一个配置编排的设置器,它与组件挂钩,两者相关联。
- 组件:纯显示层,可以单独的将其单独作为组件库来使用,渲染器在消费 Schema 后也需要直接使用;
- 属性控制器:提供一组为组件设置属性挂钩的设置器,目的是为了在编辑器中设置属性并且保存至当前的 Schema 协议当中。
物料库的设计
从设计开始,整个物料就需要与编辑器完全独立开来,编辑器通过制定的规则来加载物料组件。组件的信息与设置面板则有物料来提供,编辑器的职责属于一个上层容器,只接管相应的状态变更。
在编辑器中,我们的物料组件大体上可以分为如下几种:
- 基础物料:低代码平台提供的基础组件库,如容器、布局(分栏,栅格)等通用类型的相关组件。甚至于按钮、弹窗等组件它都是基础组件;
- 业务物料:针对于某些特定场景业务的组件,比如说商城的规格选择组件、营销活动组件等等都属于是业务集成化的组件库;
- 定制化物料:如果接入团队又或者是贡献者团队,可以根据 CLI 来创建组件插口,发布后即可通过异步资源加载的方式对接到低代码编辑器的插座口上去,实现远程物料的载入。
这里拓展一些开发业务物料的细节,在我们开发业务物料特别是营销类型物料的时候,一般都以高内聚的模式来开发,不要过多的暴露配置细节以及多组件联动的功能,因为营销类型的低代码产品都是面向运营的,在组件设计上如果有非常多定制化的内容需要配置的话,交给运营配置显然会有培训与使用成本,所以将大部分的功能以及交互收敛在独立的业务组件中,只暴露一些简单的样式配置内容即可。
组件的信息
如下图所示,编辑器在展示组件列表时,需要组件提供以下几个信息。如下图所示:
- 分类:当前所处的分类,用于后续组件分组和归类使用(非必填);
- 名称:物料在编辑器列表中显示的名称信息;
- 图标:物料在编辑器列表中显示的图标信息;
- 属性面板:通常在选中某个物料组件的时候,都会展示当前能够设置参数值的一个属性面板,它能够方便操作者可视化的为物料来设置当前的属性参数。
基于这些信息,我们基本上确定了一个物料需要的参数,下面的话我们就来定义一下MaterialType
这个接口类型:
/**
* 素材组件的类型
*/
export interface MaterialComponentType {
/**
* @name 组件名称
* @description 一个组件必须声明一个名称。
*/
displayName: string;
/**
* @name 组件icon
* @description 组件的图标,如果不存在会以NodeType首字母做示例
*/
icon?: string | React.ReactNode;
/**
* @name 分类
* @description 组件可以包含一个分类,默认为基础组件。
*/
category?: MaterialCategory;
/**
* @name 默认的props
* @description 默认props,会在初始化时设置进内容面板
*/
props?: RenderNodeType['props'];
/**
* @name 额外附加属性
*/
related: Record<string, any>;
/**
* @name 其他
* @description 留坑,方便后续其他属性的添加。
*/
[K : string]: any
}
构建物料
当组件完成后,自然而然的会在 main.ts
中导出当前的物料组件。
但是此时在设计时,需要考虑一件事情,那就是在构建时区分产物,针对不同环境下提供不同的资源。比如,在编辑器环境下,由于需要做属性设置的动作,往往物料组件上会挂载相对应的一些设置器,而在真实浏览的时候并不需要关注这方面的动作。因此设置器存放在组件上其实是占用了包大小的,因此在构建上需要做一些调整。
目前设想出了方案整体如下:
首先:物料组件的文件目录如下,将整个组件和设置器分开实现。最后在 index.ts
属性中进行挂载。
markdown
复制代码
- button - index.ts|tsx - view.ts|tsx - controller.ts|tsx - README.md - styles.ts|css
其次:在 index.ts
中,需要导出一份整合版的物料组件,将之前提到过的一些物料组件描述挂载到组件当中去。
import { View } from './view'
import { Controller } from './controller'
import { ButtonIcon } from '@ignition/dx'
export const Button = View
Button._config = {
displayName: '基础按钮',
category: 'base',
icon: <ButtonIcon/>,
props: {
type: 'primary',
},
related: {
settings: <Controller/>
}
...多余属性继续添加,
}
最后:将 config
挂载到 React 组件上,一个物料组件基本就完成了,后续就可以方便的在 React 组件上获取对应的配置信息了。
在构建时,则会在 script
中分别创建 build:views
和 build:materials
两个构建命令,分别指向如下的入口:
// npm run build:views
// src/views.tsx
import { View as Button } from './button/view.tsx'
// npm run build:materials
// src/main.tsx
export * from './button'
通过使用构建工具的多 entry
构建,就会在最终的 @ignition/materials
中分别产生 index.js
和 views.js
两个产物,一个是全量物料,一个是最小渲染组件单元。
在编辑器中使用全量物料,在真实出码和运行时环境中使用最小渲染单元的组件即可。
额外补充的是,在开发物料中,并不建议将所有物料的 Schema 协议都固定,这样的约束性太强。页面级别的 Schema 协议是可以统一的,但我们建议每个物料模块的 Schema 协议都应该做到独立且内聚,可以看出在我们的物料设计是将配置项目独立打包成一个配置模块提供给设计器使用,这样的优势在于开发物料的过程中不会有非常高的技术债务且可以快速与已有的组件库进行集成,给开发物料的同学增加最大的灵活度。
此外,配置模板里面的内容仅仅对此物料模块生效,也就是它应该提供的是具体的业务属性,比如提供某些配置可以显示隐藏物料中的模块,而样式、多语言等通用性的配置可以通过设计器在搭建的过程中统一注入。
物料管理
既然了解了物料的创建,那么如何管理之前提到过的几种物料呢?
相比于编辑器,物料的管理其实也是一个相对独立的工程。针对不同的场景可以有以下几种解决方案:
- 单独维护自己业务线的物料,通过 NPM 的形式进行迭代,发布时更新。业务组清晰的熟悉自身需要提供出去的物料能力,因此单独维护是较为稳妥的实现方式。缺点方面则是复用性差,无法做推广兼容;
- 物料中心:将物料托管至物料平台中管理,借助 CI/CD 的能力可以稳定高效的迭代物料,提供出 NPM 包与 CDN 资源,方便开发者本地依赖接入或者是异步资源加载的形式接入到编辑器内。
前端刀耕火种到如今的阶段,物料管理已经成为了团队不可或缺的一部分,从业务表现形式到应用视觉呈现。大部分的逻辑或多或少都有相似之处,尤其是对于中后台前端团队来说。往往一个需求页面,你或多或少都能在自己负责的项目或者是其他团队的项目中找到相类似的组件。
通过好的物料管理,能极大程度的为集团公司带来正向的开发效能收益,同时也能够更好的打造以公司为元素设计的品牌产品。
所以在我们的产品设计中有专门的物料平台,作为一个统一的物料管理中心,方便维护物料以及接入搭建系统。
总结
物料组件是低代码平台的弹药,编辑器则是低代码平台的枪。编辑器负责内容编排,物料组件负责能力提供,两者各司其职。基于上述方案设计,物料组件既可以是编辑器搭建组件,同时也可以做为组件库使用,充分发挥其特定价值,实现利益最大化。
此章节的内容会随着项目的更新进度不断优化
写在最后
如果你有什么疑问或者更好的建议,欢迎在评论区提出。 👏