随着平台能力的扩展,我们的 CLI 工具 dnf 的子命令数量从最初的 5 个增长到了 30 多个。所有子命令都打包在一个 npm 包里,安装体积越来越大,更新频率也变得不一致——有的子命令一个月迭代好几次,有的半年不动一行代码。
更麻烦的是职责边界的问题。不同的子命令由不同的团队维护,但发布节奏被绑定在一起。团队 A 想发一个 hotfix,要等团队 B 的代码也通过测试才能一起发版。这种耦合严重拖慢了迭代效率。
我们的方案是把 dnf 改造为一个轻量级的命令分发器。核心包只包含命令路由、版本管理和插件加载三个功能,实际的业务逻辑以独立的 npm 包形式发布。当用户执行 dnf deploy 时,核心包会检查本地是否有 @dnf/plugin-deploy,没有则自动安装。
动态加载带来了几个好处:每个子命令可以独立发版、独立测试;核心包体积从 80MB 缩减到不到 5MB;新团队可以自行开发和发布子命令,不需要向核心仓库提交 PR。
实现过程中有不少细节需要处理。版本解析策略是第一个——插件之间可能依赖不同版本的公共库,需要妥善处理依赖冲突。我们采用了每个插件独立 node_modules 的隔离方案,虽然占用更多磁盘空间,但避免了版本冲突的噩梦。
另一个考量是离线场景。在某些受限的网络环境下,动态安装插件行不通。我们提供了 dnf bundle 命令,可以将指定的插件集预打包成一个离线安装包,适配 CI 环境和内网开发场景。
工具的插件化不仅是技术问题,更是生态问题。我们定义了清晰的插件开发规范和脚手架,提供了 dnf create-plugin 命令帮助新团队快速启动。同时建立了插件市场,让团队可以发现和复用其他团队开发的能力。这种开放的模式让 CLI 工具从一个团队的产品变成了整个组织的协作平台。