pnpm install && pnpm run build。保留本课创建的 scratch-plugin/ 目录——L13、L14 会继续在它上面做实验。在仓库根目录下建练习目录,目标结构:
mkdir -p scratch-plugin/src
scratch-plugin/
├── cordis.yml # 声明"挂哪些插件"的配置(下一步创建)
└── src/
└── my-plugin.ts # 你的插件本体
创建 scratch-plugin/src/my-plugin.ts:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
// 走到这里,inject 声明的依赖都已就绪(本例没有依赖)
console.log('[hello-plugin] plugin loaded!')
}
| 成员 | 作用 | 可以省吗 |
|---|---|---|
name | 插件名(日志、配置行引用用它) | 建议总是写 |
inject | 依赖声明:数组里列出必需的服务名 | 无依赖可省 |
apply(ctx) | 安装函数:一切注册发生在里面 | 不可省,这是插件的全部 |
先在仓库根目录跑 pwd 拿到绝对路径,然后创建 scratch-plugin/cordis.yml(路径必须是绝对的):
- insert:
- id: hello
name: '/把这里换成pwd输出的绝对路径/scratch-plugin/src/my-plugin.ts'
pnpm dsh web --patch ./scratch-plugin/cordis.yml
启动时终端会打印 [hello-plugin] plugin loaded!——你的第一个插件已在一棵完整的产品插件树里运行。相当于给一辆行驶中的车换了个零件。
把插件改成会心跳的版本(ctx.effect 的标准用法):
export function apply(ctx: Context) {
ctx.effect(() => {
const timer = setInterval(() => {
console.log('[hello-plugin] heartbeat')
}, 5000)
return () => clearInterval(timer) // 卸载时自动执行
})
}
任何注册在 ctx 上的东西——监听器、工具、定时器——插件卸载时自动清理,无需手写 removeListener / clearInterval。
要用别人的服务(比如工具注册表),在 inject 里声明:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-tool-plugin'
export const inject = ['tools'] // ← 等到 ctx.tools 就绪才加载我
export function apply(ctx: Context) {
ctx.tools.register(/* ... */) // 此处 ctx.tools 必然可用
}
// ① 函数形式(本课主角,大多数场景够用)
export const name = 'my-plugin'
export function apply(ctx: Context) { /* ... */ }
// ② 对象形式:同样三件套,收进一个对象
export default {
name: 'my-plugin',
inject: ['tools'],
apply(ctx: Context) { /* ... */ },
}
// ③ 类形式:继承 Service,适合"给别人提供服务"(L16 专讲)
import { Service } from '@deepseek-ai/cordis'
export default class MyService extends Service {
static inject = ['tools']
constructor(ctx: Context) { super(ctx, 'myService') }
}
name/inject/Config/apply 且没有默认导出。两种形态混用会让 Loader 静默丢弃函数插件的命名空间(仓库 postmortem/0001 记录了这次事故)。结论现在记,原理 L16 讲。[hello-plugin] plugin loaded!。my-plugin.ts 里的日志文案并保存,观察新版本被加载、旧注册被自动清理。inject 加上 ['tools'],重启确认依然加载成功(说明 tools 服务在你的插件之前就绪)。