运行 nub <verb>,当 nub 不认识该动词时,它解析名为 nub-<verb> 的可执行文件,然后用原封不动转发的其余参数运行它。这与 git-foocargo-foo 背后的约定相同。

nub changeset publish      # 运行 nub-changeset publish
nub release --tag beta     # 运行 nub-release --tag beta

插件只是安装 nub-<verb> bin 的包——没有插件清单、没有注册步骤、没有声明它的配置字段。像任何其他依赖一样安装它,动词就工作了。

nub add -D nub-changeset   # 提供 nub-changeset bin
nub changeset              # 现在解析并运行它

解析

带前缀的名称按顺序在两处解析:

  • node_modules/.bin — 项目本地 bin,从当前目录向上遍历(与 nub runnubx 使用相同的链)。
  • PATH — 全局安装的插件。

只探测带前缀的 nub-<verb> 名称——从不探测裸动词。拼写错误的命令如 nub bnuild 解析无果并打印通常的不是命令错误;它不能回退到 PATH 上的随机 bnuild 二进制文件。

内置始终优先

插件永远不能遮蔽内置动词。原生命令和包管理器动词在任何插件查找之前匹配,所以 nub runnub installnub add 等始终分派到 nub 自身,即使 nub-run bin 存在于 node_modules/.bin 中。回退仅对 nub 没有内置的动词触发。

脚本名称取相同优先级。命名本地 package.json 中脚本的动词,或约定名称 devbuildteststartlint 之一,在插件查找之前解析为 nub run <verb> 提示——所以 nub-buildnub-test 插件从不会通过其裸动词到达。为不是脚本的东西命名插件(nub-changesetnub-release),或通过 nub run 或直接按其 bin 调用脚本命名的插件。

编写插件

插件是名为 nub-<verb> 的可运行可执行文件——编译的 JavaScript bin 或原生二进制文件,与任何其他 node_modules/.bin 条目或 git/cargo 子命令相同。没有插件特定的构建目标:用 TypeScript 编写并发布编译输出,与你发布任何其他 bin 的方式完全一样。安装的 bin 不被转译——保持 node_modules 与纯 Node 相同的字节对等边界——所以实际运行的是 JavaScript 或原生。

JavaScript 插件在 nub 的运行时增强下运行,与 nub run 运行脚本完全一样——版本门控的全局变量存在。原生可执行文件直接运行。插件的退出码就是 nub 返回的。

#!/usr/bin/env node
// nub-changeset — 用 TypeScript 编写,以编译 JS 发布
const target = process.argv[2] ?? "staging";
console.log(`releasing ${target}`);

要以禁用增强运行插件,在动词前传递 --node——nub --node changeset,与文件运行使用的位置相同。动词之后的任何内容原封不动转发给插件,所以尾随的 nub changeset --node 作为参数到达插件且不禁用增强。参见运行时概览了解约定。

相关

  • 包运行器nubx,用于按名称运行工具而不安装为子命令。
  • 运行脚本nub run,共享 bin 解析链。
  • 运行时 — TypeScript 优先执行和 JS/TS 插件继承的增强。