05 · 配置校验与 PENDING 诊断
目标:掌握插件配置的 schema 校验(坏配置精确报错)与「插件没输出也没报错」的第一排查手段——fiber 状态。 对应快速入门项目:
npm run lesson:05/npm run lesson:06
实例 A:配置校验(schemastery)
插件导出 Config:既是 TS 接口,也是同名运行时 schema(Cordis 接受任意 Standard Schema 验证器,dsh 生态用 Schemastery)。
// config-demo.ts
import type { Context } from 'cordis'
import Schema from 'schemastery'
export const name = 'config-demo'
export interface Config {
greeting: string
targets: string[]
}
export const Config: Schema<Config> = Schema.object({
greeting: Schema.string().default('Hello'),
targets: Schema.array(String).default(['world']),
})
export function apply(ctx: Context, config: Config) {
for (const target of config.targets) {
console.log(`${config.greeting}, ${target}!`)
}
}# cordis.yml —— 未提供 greeting,schema 默认值会补齐
- name: './config-demo.ts'
config:
targets: ['cordis', 'koishi', 'deepseek-harness']运行 npm run lesson:05:
Hello, cordis!
Hello, koishi!
Hello, deepseek-harness!
apply(ctx, config) 前完成校验:apply 始终收到完整且经过验证的配置,插件绝不会带残缺配置启动。
坏配置精确报错:把 targets 改成 'not-an-array' 再运行:
ValidationError: invalid config:
- $.targets expected array but got not-an-array (at targets)
fiber 进入 FAILED,启动器打印错误后以状态码 1 退出。
计算得到的配置值:本仓库的 loader 支持 !!js 标签,仅在 config 与条目 disabled 字段内有效:
- name: './config-demo.ts'
config:
greeting: !!js process.env.DEMO_GREETING ?? 'Hello'disabled: !!js ... 在每次挂载决策时求值,可按平台/环境门控一行。
实例 B:PENDING 诊断(fiber 状态机实战)
依赖驱动加载的另一面:inject 了无人提供的服务时,插件一直等待、不输出、不报错。PENDING 是合法状态(提供方可能稍后才挂载),所以「插件没输出」时要主动查。
// needs-timer.ts —— inject 了无人提供的服务 → 永远 PENDING
import type { Context } from 'cordis'
export const name = 'needs-timer'
export const inject = ['timer']
export function apply(ctx: Context) {
console.log('needs-timer loaded')
}// diagnose.ts —— 枚举插件注册表,找出卡在 PENDING 的 fiber
import { FiberState, type Context } from 'cordis'
export const name = 'diagnose'
export function apply(ctx: Context) {
setTimeout(() => {
for (const runtime of ctx.registry.values()) {
for (const fiber of runtime.fibers) {
if (fiber.state === FiberState.PENDING) {
console.log(`${fiber.name} is PENDING — a required service is missing`)
}
}
}
}, 500)
}运行 npm run lesson:06:
needs-timer is PENDING — a required service is missing
复活现场演示:给 cordis.yml 加一行 - name: '@cordisjs/plugin-timer',needs-timer 立即加载——依赖恢复自动加载,无需任何手动干预。
诊断技巧:不加 PENDING 过滤条件遍历 ctx.registry,还会看到 Loader、Include 自身也处于 ACTIVE——配置文件本身也是通过插件挂载的。
动手练习
- 给
Config加一个必填字段(Schema.string()不带.default())且 yml 不提供,观察报错定位到缺失字段 - 写一个诊断器变体:打印所有 fiber 的名字与状态,理解注册表全貌
- 给 lesson:06 补上 timer 提供方后再运行,确认诊断器不再报 PENDING——依赖跟踪是持续双向的
上一课:04-events | 下一课:06-composition-hmr