Appearance
模板与插件
当一条 workflow 变成团队内重复出现的模式时,真正有价值的不是再复制一份文件,而是把结构提炼出来
模板适合解决什么问题
模板本质上是 workflow 工厂
适合这类场景
- 发布流程有固定骨架
- 部署流程按服务名生成不同实例
- 故障处理流程按严重级别套出不同步骤组合
ts
import {
createWorkflowTemplateCatalog,
defineStep,
defineSteps,
defineWorkflowTemplate,
} from 'clack-kit';
const deployTemplate = defineWorkflowTemplate({
id: 'deploy-service',
title: '部署服务',
create(input: { service: string }) {
return {
id: `deploy-${input.service}`,
steps: defineSteps([
defineStep.text({
id: 'service',
message: '服务名',
defaultValue: input.service,
}),
]),
title: `部署 ${input.service}`,
};
},
});
const catalog = createWorkflowTemplateCatalog([deployTemplate] as const);插件的四个扩展点
WorkflowPlugin 目前最重要的扩展点有四个
| 扩展点 | 作用 |
|---|---|
| setup | 注册自定义步骤处理器 |
| extendContextTools | 往 context.tools 挂新能力 |
| wrapRenderer | 包裹默认 renderer |
| wrapExecutor | 包裹命令执行器 |
setup 和 registerStepHandler
自定义步骤类型时,入口在 setup
ts
const plugin = {
name: 'approval-step',
setup(api) {
api.registerStepHandler('approval', async ({ context, step }) => {
context.note(`审批人:${String(step.approver)}`, '审批步骤');
return {
approved: true,
};
});
},
};这种方式适合把领域步骤抽出来,例如审批、工单、告警确认
extendContextTools 的边界
适合挂那些跨多条 workflow 复用、又不想每次手动 import 的工具函数
例如
- 读取仓库约定文件
- 访问团队内部配置
- 包装一层常用命令
wrapRenderer 和 wrapExecutor
这两个扩展点更偏底层
wrapRenderer
适合统一修改终端表现,例如包一层额外提示、收集埋点或替换局部渲染行为
wrapExecutor
适合统一修改命令执行行为,例如记录额外监控信息、接入另一套命令后端或注入环境变量
executorType 和自定义 executor 的关系
- executorType 用来选择内置执行器,默认是 node
- executor 用来完全替换执行器
- wrapExecutor 包裹的是最终选定的执行器
这三者的优先级关系明确后,执行层扩展就不容易绕乱
模板和插件怎么配合
一个常见组合是
- 用模板沉淀流程骨架
- 用插件补统一能力和领域步骤
这样做的好处是
- 模板负责结构复用
- 插件负责运行时能力复用
- 两者职责分开,改动范围更可控