dsh出来也有一段时间,个人比较好奇的是它宣传的两个概念 - 时空可组合性和一切皆插件。可惜社区一堆推销plugin的,没见几篇深入这两个概念的。带着这两个兴趣点,就想走走插件的制作和HMR流程,探究一二。
插件化设计
第一步打开了官网,并首先了解到了两点:
1. 插件框架是基于Cordis的。 2. 所有插件的开发入口最终都汇聚到apply函数和Context参数
export function apply(ctx: Context, config: Config) { //从context去获取其它插件.}然后又了解到了插件之间角色有provider和consumer区分,当然也可以同时是二者。作为consumer时,需要用显式声明依赖,如下:
export const inject = ['tools'] //必需依赖const metrics = ctx.get('metrics') //可选依赖作为provider时,需要合并声明,这样consumer才能从context入口访问到:
declare module '@deepseek-ai/cordis' { interface Context { metrics: MetricsService }}到这里,就有点一切皆插件的意思了,协作的基本单元都是插件,而且插件间也能通过事件监听和广播的方式实现通信:
ctx.on('event-name', (payload) => { // Handle the event.})ctx.emit('event-name', payload)题外:还有个比较有意思的是“能力的三层拆分”这里,一眼熟悉的OOP的依赖倒置(DIP)和接口分离原则。
插件开发
插件开发主体跟传统npm包开发区别不大,声明依赖,暴露入口,输出目录即可:
{ name: ID + '/client', entry: { client: 'src/client/index.ts' }, outDir: 'lib', format: 'cjs', platform: 'browser',}重点是要提供dsh声明,这样dsh才能识别它是一个dsh插件.
"dsh": { "bundle": { "patch": "./cordis.patch.yml" }}相应的在patch配置处声明你的意图和id,名称等信息,用于加载到运行时上下文.
- insert: - id: ui-wallpaper name: 'dsh-wallpaper'插件安装
安装基于profile,基础命令如下:
npx @deepseek-ai/dsh plugin --profile web add <本地路径或git地址>注:当添加的路径是本地client插件时,插件dst变更就能同步HMR到web端,这也是我了解到的第一个HMR方式。
不重启插件上下线
应该说是一个很常见的需求,目前探索出来的不重启插件上下线的方式是编辑~/.dsh/profiles/web/cordis.patch.yml。在npx @deepseek-ai/dsh plugin --profile web add之后追加insert配置以上线:
- insert: - id: ui-pet name: 'dsh-pet'下线则设置显式配置disabled: true
- id: ui-pet disabled: true注:只对没声明 dsh.bundle.patch也就是手动挂载的插件成立
总结
总体体验下来是插件化的设计harness的定制化自由度很高,但这份自由度的必要性有多高不得而知。没什么idea,最后也就只能想到基于turn start/end的事件做只pet cat,提供点情绪价值了...


夜雨聆风