背景
FlowGram 是一套基于节点编辑的流程搭建引擎,帮助开发者快速创建固定布局或自由连线布局模式的流程,并提供一套交互的最佳实践, 很适合有明确输入和输出的可视化工作流。
Flowgram 详细介绍见:flowgram.ai/guide/intro...
Flowgram 即便提供了高灵活度的定制能力,但是实际开发过程中依旧存在问题:
- 高昂的学习成本: 开发者需要深入理解一系列复杂概念,如实体组件系统 (ECS)、抽象语法树 (AST) 和控制反转 (IoC) 等。
- 开发效率瓶颈: 对于一些常见的业务场景,从零开始开发新物料的人力成本较高,而这些需求(如变量选择器、JsonSchema 编辑器等)在不同项目中又高度相似。

为了解决这些痛点,我们引入了物料库。 物料库作为 Flowgram 核心引擎之上的一个"外观层"(Facade),将底层的复杂性进行封装,以更直观、更易用的方式提供给开发者,从而极大地提升了开发体验和效率。

我们的物料库在设计上遵循两个核心原则:
- 代码简洁易读: 物料的代码应该专注于其核心功能,避免过度封装和复杂的业务逻辑,使其易于理解和维护。
- 鼓励通过 Copy-Paste 实现定制: 当官方物料无法满足特定的业务需求时,我们不推荐通过增加复杂的配置项来解决,而是鼓励开发者使用我们的命令行工具(CLI)将物料代码 copy-paste 到本地,进行二次开发。
物料库详见:flowgram.ai/guide/advan...
物料库建设上的一些实践
CLI 复制代码
背景
对于需要实现定制需求的用户,CLI 可以方便的把对应的物料从物料库中拷贝到用户自己的代码仓库里面,并自动处理依赖:
如下图所示,用户需要定制物料B 的逻辑,则他可以使用 CLI 将物料B复制到自己的仓库里,CLI 在复制时,会自动处理物料 B 对物料 C 的依赖:

Case Run Down
假设我想要定制 condition-row 组件:

- 运行 npx @flowgram.ai/form-materials ,选择 condition-row 组件:

- 代码会自动复制到用户代码仓库的 form-materials/components/condition-row文件夹:

- ConditionRow 代码其中对 form-materials 中的其他物料的依赖也会自动更新:

- 同时 CLI 会自动在当前项目中,安装相关的依赖项:

具体实现
CLI 复制的整体时序图如图所示:

组件物料的依赖注入
背景
在官方物料库中,组件物料和组件物料之间往往存在复杂的依赖关系,如图所示:

在这样一张复杂的依赖网络中,一些物料组件,如 VariableSelector、TypeSelector,往往处在依赖链的顶端,被大量其余物料直接或者间接依赖。
这些复杂的依赖链路会使这些处在依赖链顶端的物料定制难度加大。
以 VariableSelector 组件为例,他被 DynamicValueInput、BatchOutputs、ConditionRow 直接依赖,又被 InputsValues、ConditionRow 间接依赖。
- 用户想要定制 VariableSelector 一个样式,于是使用 CLI 将 VariableSelector 拷贝到本地,并加入样式定制代码:

- 用户在使用过程中,DynamicValueInput、BatchOutputs、ConditionRow 等物料直接依赖了VariableSelector,但是没有应用最新的样式。于是将 DynamicValueInput、BatchOutputs、ConditionRow 物料++也拷贝到本地,更改依赖++到用户定制后的 VariableSelector:

- 用户再次发现被 InputsValues、ConditionRow等物料还通过 DynamicValueInput 间接依赖了 VariableSelector,没有应用最新的样式,于是把 InputsValues 也拷贝到本地,并更新依赖:

解决思路
依赖反转原则(DIP)主要想告诉我们的是,如果想要设计一个灵活的系统,在源代码层次的依赖关系中就应该多引用抽象类型,而不是具体实现。 《架构整洁之道》
以 VariableSelector 为例,我们让所有物料对 VariableSelector 的依赖,改为对一个抽象的 VariableSelectorRenderKey 的依赖:

如图所示,基于该改造后:
-
上层所有复杂的物料,不直接依赖 VariableSelector,而是依赖一个抽象的 VariableSelectorRenderKey
-
物料库中的 VariableSelector实现被绑定到 VariableSelectorRenderKey 上
-
当用户要定制VariableSelector物料时,将用户修改后的CustomVariableSelector,绑定到 VariableSelectorRenderKey 上即可
Case Run Down
物料库视角: 以 VariableSelector 为例,我希望 VariableSelector 是可依赖注入的,我可以在 VariableSelector 上配置一个 renderKey,接着使用 createInjectMaterial 高阶组件进行封装,封装为 InjectVariableSelector:

使用 createInjectMaterial 将物料封装为可依赖注入的物料
在物料库中,其他用到 VariableSelector的物料,都将引用改为 InjectVariableSelector:

引用 InjectVariableSelector,而不直接是 VariableSelector
用户视角: 在物料库将 VariableSelector 修改为可依赖注入后,我们首先通过 CLI 将 VariableSelector 拷贝到本地:


假设我的修改是把变量选择器的变量选择后的背景改为红色 那么系统中直接使用到定制后的变量选择器的地方会变成红色,但是物料库中依赖VariableSelector的地方,还是原来的样式,如图所示:

用户需要在use-editor-props 中,完成 VariableSelectorRenderKey 与用户定制 MyVariableSelector 之间的绑定:

经过修改后,系统中所有依赖 VariableSelector 的其它物料中,变量选择器的背景都变成了红色,如图所示:

实现
createInjectMaterial 的实现代码见 inject-material/index.tsx
时序图如下所示:

和 ShadeCN 的比对
ShadeCN 是一个广受欢迎的组件库,它和我们的物料库一样,也提供了 copy-paste 的方式让用户使用组件。然而,两者在设计上存在一些关键差异:
- 架构差异: ShadeCN 倾向于提供原子化、功能单一的组件。而 flowgram 物料库中 物料相互依赖,因此额外提供了依赖注入等能力实现更灵活的定制,CLI 也增加自动处理依赖的能力
- 生态集成: Flowgram 物料库是为 Flowgram 生态量身打造的,能够无缝地利用 Flowgram 核心引擎提供的状态管理、逻辑编排等能力,这是通用组件库无法比拟的。
- 物料差异: ShadeCN 以组件物料为主,而 flowgram 物料库结合自己的节点引擎,提供了插件物料、副作用物料、校验器物料等多种物料