0
0
0

Cordis 插件框架核心概念

2026-08-14
2026-09-07
Cordis 插件框架核心概念
文章摘要
|

入门02:Cordis 插件框架核心概念

如果你是前端开发者,可以把 Cordis 理解成:"一个专门用来写插件的框架,相当于 Vue 的插件系统 + React 的 useEffect + Node.js 的 EventEmitter 合体。"

DeepSeek Harness 所有功能都跑在 Cordis 之上。不懂 Cordis,就看不懂 Harness。


1. Cordis 到底是个啥?

Cordis 是一个"元框架"——专门用来构建插件化应用的框架。它的核心思想一句话:

一切皆插件,插件之间通过依赖注入互相连接,通过事件系统互相通信。

用前端话翻译:

前端概念Cordis 对应说明
Vue 的 provide/injectService你提供个服务,别人注入使用
React 的 useEffectFiber注册副作用,卸载时自动清理
Vue 的 $emit/$onEvents事件总线,但多了 5 种模式
Vue 的 app.use()Registry注册插件
React 的 Context APIContext全局上下文,子组件继承

Cordis 的源码在项目的 vendor/cordis/ 目录下,有兴趣可以翻翻。


2. 五大核心概念(用前端例子讲)

Context - 相当于 Vue app 实例
Service - 相当于 provide/inject 的服务
Events - 相当于事件总线
Fiber - 相当于 useEffect 的生命周期
Registry - 相当于 app.use

2.1 Context(上下文)— 一切的中心

你可以把 Context 想象成一个"万能背包"——你想要啥,直接从包里掏。

Context 是 Cordis 最核心的概念。它实际上是一个 JavaScript Proxy(代理对象),你访问 ctx.xxx 时,它会自动查找有没有注册过叫 xxx 的服务。

这就像 Vue 的 app.config.globalProperties + React 的 createContext 合体,但更智能——它自动查找,不用你手动传递。

// 就像 Vue 的 app.provide('logger', ...)
const ctx = new Context()

// 放一个服务进去
ctx.provide('logger', new LoggerService())

// 用的时候直接拿,就像 app.config.globalProperties.logger
ctx.logger.info('hello')  // Proxy 自动找到 logger

// 创建子上下文,相当于 Vue 的组件嵌套作用域
const child = ctx.extend()
child.provide('logger', new CustomLogger())  // 子上下文覆盖父的 logger

2.2 Service(服务)— 封装一个能力

就像你写一个 Vue composable 然后 provide 出去,整个应用都能用。

Service 是封装"能力"的基本单位。你继承 Service 类,传个名字,它就自动注册到 ctx 上了。

import { Service } from 'cordis'

// 定义一个服务,就像写一个 Vue composable
class LoggerService extends Service {
  constructor(ctx: Context) {
    // 注册到 ctx.logger,就像 provide('logger', this)
    super(ctx, 'logger')
  }

  info(msg: string) {
    console.log(`[INFO] ${msg}`)
  }
}

// 使用
const ctx = new Context()
const logger = new LoggerService(ctx)
ctx.logger.info('hello')  // 自动找到,就像 inject('logger')

关键点

  • super(ctx, 'logger') 自动注册到 ctx.logger,相当于 provide('logger', this)
  • 同一个名字的服务可以被覆盖——就像你用 app.provide 覆盖父组件的 provide
  • 这其实就是"依赖注入"——你不需要自己 new,框架帮你注入

2.3 Fiber(纤维)— 插件的"生命周期"

这玩意儿就像 React 的 useEffect + useCleanup。插件加载时执行初始化,卸载时自动清理,防止内存泄漏。

每个插件启动时都会创建一个 Fiber,管理它的"生老病死":

启动
就绪
销毁
出错
销毁
未激活
激活中
运作中
已销毁
出错

Fiber 最重要的机制是 Effect(副作用)

// 这不就是 React 的 useEffect 吗?
ctx.effect(() => {
  // 插件激活时运行
  const timer = setInterval(() => {
    console.log('心跳')
  }, 1000)

  // 返回清理函数,插件销毁时自动调用
  return () => {
    clearInterval(timer)  // 防止内存泄漏!
  }
})

React 开发者看到这个应该很亲切——useEffect 也是返回清理函数,组件卸载时自动执行。

2.4 Events(事件)— 插件间的通信

就像 Vue 的 $emit / $on,但 Cordis 多了 5 种模式,比 EventEmitter 更灵活。

// 监听事件,就像 Vue 的 $on
ctx.on('my-event', (data) => {
  console.log('收到事件:', data)
})

// 触发事件,就像 Vue 的 $emit
ctx.emit('my-event', { message: 'hello' })

Cordis 支持 5 种事件模式,其中最重要的是 Waterfall(流水线)

模式咋工作的像什么
emit同步依次执行广播喇叭,大家都听到
parallel异步同时执行同时发令枪
serial前一个完事下一个接上接力赛跑
bail谁先返回结果就用谁的竞速模式
waterfall前一个的输出是后一个的输入流水线作业

Waterfall 是 Harness 最重要的扩展点,几乎所有核心流程都通过它暴露"钩子":

// Waterfall 就像 Express 的中间件
ctx.waterfall('my-pipeline', (input) => {
  // 处理 input,返回处理后的结果
  return { ...input, extra: '新加的数据' }
})

插件的执行流程就像 Express 中间件一样,层层传递,每层可以修改、增强、甚至中断。

2.5 Registry(注册表)— 插件管理器

就像 Vue 的 app.use(MyPlugin),注册了就生效。

// 启动一个插件,就像 Vue 的 app.use
const fiber = ctx.plugin(MyPlugin, { /* 配置 */ })

// 停止插件
fiber.dispose()

Cordis 的 Loader 扩展了注册表,支持从 YAML 配置文件声明式加载插件:

# cordis.yml —— 就像 Vue 的配置文件
plugins:
  - name: logger
    path: @deepseek-ai/dsh-logger
    config:
      level: info

  - name: tools
    path: @deepseek-ai/dsh-tools

3. 插件的完整生命周期

插件Fiber注册表Loader配置文件插件Fiber注册表Loader配置文件运行中...读取配置注册插件创建 Fiber注入依赖执行初始化注册副作用标记激活触发销毁执行清理标记已销毁

4. 类型安全(TypeScript 友好的)

Cordis 支持声明合并,用 ctx.xxx 时有完整的类型提示:

// 在你包的 index.ts 里
declare module 'cordis' {
  interface Context {
    myService: MyService
  }
}

这样 ctx.myService 就能自动推断出类型,不用 as any


5. 在 Harness 里实际怎么用?

import { Context, Service } from 'cordis'

// 1. 定义服务接口(就像定义接口类型)
export class MyService extends Service {
  constructor(ctx: Context) {
    super(ctx, 'myService')
  }

  abstract doSomething(): Promise<string>
}

// 2. 实现服务(就像写个 class 实现接口)
export class MyServiceImpl extends MyService {
  constructor(ctx: Context) {
    super(ctx)
    // 声明我需要 logger 和 storage
    ctx.inject(['logger', 'storage'])
  }

  async doSomething(): Promise<string> {
    ctx.logger.info('做事ing')
    return 'done'
  }
}

// 3. 类型声明(让 TS 知道 ctx.myService 的类型)
declare module 'cordis' {
  interface Context {
    myService: MyService
  }
}

要点总结(用前端话)

  • Context = Proxy 代理的"万能背包",ctx.xxx 自动找服务,像 Vue 的 provide/inject 但更智能
  • Service = 继承 Service 类自动注册,像 Vue composable 但全局可用
  • Fiber = 插件的生命周期,ctx.effect() 就像 useEffect,自动清理
  • Events = 5 种事件模式,Waterfall 最常用,像 Express 中间件
  • Registry = ctx.plugin() 注册插件,像 app.use()
  • 所有 Harness 功能都是 Cordis 插件

进阶阅读

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!