06 · 组合元数据与热替换(HMR)
目标:把
cordis.yml当应用来管理——条目元数据(id/disabled/组/isolate)与保存即生效的热替换。 对应快速入门项目:npm run lesson:07(常驻进程,Ctrl-C 退出)
条目元数据
配置项不只有 name 和 config:
- id: greeter # 稳定标识:让 loader 区分「修改」与「先删再加」
name: './greeter.ts'
- id: consumer
name: './consumer.ts'
disabled: true # 保留条目但卸载插件id:稳定标识。HMR/loader 按iddiff,只动变化的条目;没写id的条目每次读取都获得新 id,任何 yml 编辑都会导致它被删了重挂disabled: true:卸载插件但保留条目;改回后插件及所有因依赖其服务而 PENDING 的插件再次加载- 组:嵌套一份配置项子列表,作为整体单元加载/卸载
isolate:给组内某服务名提供独立实例——两组可以各自看到配置不同的shell提供方,互不影响
实例:HMR 保存即热替换
原理一句话:卸载释放 effect(第 02 课)+ 依赖驱动加载(第 03 课),所以热替换 = 先卸载再加载。
# cordis.yml —— HMR 依赖两个基础设施插件(体现「无特权核心」)
- id: logger
name: '@cordisjs/plugin-logger-console' # hmr 通过 logger 服务记日志,没它看不到 hmr 消息
- id: timer
name: '@cordisjs/plugin-timer' # hmr inject timer 做去抖,缺了永远 PENDING 且无提示
- id: hmr
name: '@cordisjs/plugin-hmr'
config:
root: ['.']
- id: hello
name: './hello.ts'运行(npm run lesson:07 已内置 --expose-internals——HMR 需读取 Node loader 内部结构,缺了直接报 --expose-internals is required for HMR service):
npm run lesson:07保持进程运行,编辑 hello.ts 的日志文案并保存:
hello from my first cordis plugin
2026-07-22 15:44:36 [I] hmr watching [ '.' ]
2026-07-22 15:44:39 [I] hmr reload plugin at hello.ts
hello from my EDITED plugin
旧实例先卸载(其全部 effect 回卷),新代码随后加载,apply 再次运行。
编辑 cordis.yml 本身也触发更新:按 id diff,只挂载/卸载/重配变化的部分——这就是上面条目都显式带 id 的原因。
两个隐藏依赖的教训
HMR 插件自身的依赖正好是本课两个知识点的实战:
- 没有
logger-console→ hmr 消息打不出来(logger 是服务,也是插件) - 没有
timer→ hmr 永远 PENDING 且毫无提示——用第 05 课的诊断器可以查出来
动手练习
- 把
hello条目的id删掉,运行中随便在 yml 加一行注释保存,观察 hello 是否被重挂(每次都会——没有稳定 id) - 给
hello条目加disabled: true保存,观察卸载日志;删掉该字段保存,观察复活 - 把
logger-console注释掉重启,体会「hmr 明明在工作却看不到任何日志」的静默失败
上一课:05-config-diagnose | 下一课:07-into-harness