开发者体验 CLI:错误提示要能直接指向下一步
开发者体验 CLI:错误提示要能直接指向下一步
一、CLI 的体验常常坏在失败时
很多内部工具或独立产品会提供 CLI:初始化项目、生成组件、同步配置、发布静态资源。成功路径通常很顺,一条命令跑完,终端输出绿色提示。但真正决定开发者体验的,是失败时工具能不能说清楚下一步。
只输出Error: failed或一长串堆栈,等于把排查责任全部丢给用户。好的 CLI 错误提示应该说明发生了什么、可能原因是什么、用户可以执行哪条命令继续。
二、错误要分层
flowchart TD A[用户输入] --> B[参数校验] B --> C[环境检查] C --> D[业务执行] D --> E[外部服务] B --> F[可修复错误] C --> F E --> G[重试或降级]CLI 错误大致可以分成参数错误、环境错误、权限错误、网络错误和内部错误。不同错误需要不同提示。参数错误要给示例,环境错误要告诉缺什么,权限错误要说明申请方式,网络错误要提供重试建议。
class CliError extends Error { constructor( message: string, public code: string, public suggestion: string ) { super(message) } }统一错误类型能让输出风格一致,也方便测试。
三、提示要给可执行动作
function printError(error: CliError) { console.error(`Error [${error.code}]: ${error.message}`) console.error(`Next: ${error.suggestion}`) } throw new CliError( "Missing project config: dx.config.json", "CONFIG_NOT_FOUND", "Run `dx init` in the project root, then retry this command." )“请检查配置”太宽泛。更好的提示是直接告诉用户文件名、预期位置和下一条命令。如果涉及多个选择,也要按最可能的路径排序,而不是一次塞给用户十条建议。
对于高频错误,可以在提示里加文档链接。但链接不能代替本地说明。用户在终端里遇到错误,最希望先得到一条能马上执行的动作。
除了单次错误提示,CLI 还应该支持交互式修复。比如检测到配置文件缺失,不只是建议跑dx init,而是直接询问用户是否现在生成,省去用户手动输入下一条命令的步骤:
async function handleConfigMissing() { const answer = await prompts({ type: "confirm", name: "init", message: "未找到 dx.config.json,是否现在生成默认配置?", initial: true, }) if (answer.init) { const config = generateDefaultConfig(process.cwd()) await fs.writeFile("dx.config.json", JSON.stringify(config, null, 2)) console.log("已生成 dx.config.json,请检查配置后重新运行命令。") } else { console.log("你可以手动创建 dx.config.json 后再试。参考文档: https://docs.example.com/dx-config") } }这个流程在实际项目里减少了大量文档查阅时间。用户不需要切到浏览器搜索配置格式,CLI 直接在终端里把默认配置写好,用户改几个值就能继续。但要注意默认配置不能把敏感信息写入,比如 API Key 或数据库密码,应该用占位符提示用户自行填写。
还有一类高频错误是 Node 版本不兼容。CLI 应该在启动阶段就检查版本:
function checkNodeVersion(required: string) { if (!semver.satisfies(process.version, required)) { throw new CliError( `当前 Node 版本 ${process.version},需要 ${required}`, "NODE_VERSION_MISMATCH", `使用 nvm install ${semver.minVersion(required)?.version} 或升级 Node 后重试。` ) } }早期版本没做这个检查,用户会遭遇各种奇特的SyntaxError和undefined is not a function,但错误堆栈完全不指向版本问题。加了这个入口检查后,这类无效排查时间直接归零。
四、CLI 也要测试失败路径
成功路径测试很容易写,失败路径更值得测。比如缺少配置文件、Node 版本过低、Token 失效、网络超时、目标目录不可写,这些都是用户真实会遇到的问题。
it("prints actionable message when config is missing", async () => { const result = await runCli(["build"], { cwd: emptyProject }) expect(result.stderr).toContain("CONFIG_NOT_FOUND") expect(result.stderr).toContain("dx init") })测试不必断言完整文案,但应断言错误码和关键下一步。这样改文案不会频繁破坏测试,错误体验的核心又能被保护住。
还要给 CI 留一个快照检查,确保 CLI 输出不会突然混入调试日志、未处理堆栈或敏感路径。面向开发者的工具,终端输出就是产品界面。
失败路径测试最好覆盖用户最常见的环境差异:Mac 上能跑但 Linux CI 上权限不足、本地有全局安装的依赖但 CI 里缺失、windows 路径分隔符与 Unix 不同、代理环境下网络请求走不出。这些看起来是环境问题,但 CLI 的态度应该是"检测到差异就给出明确指引",而不是把错误信息完全交给操作系统。
五、总结
开发者体验 CLI 的重点不只是命令能跑通,更是失败时能把用户带回正确路径。
把错误分类、给出错误码、提供可执行下一步,并测试失败路径,CLI 才会从"脚本集合"变成可靠的工程工具。好 CLI 的标志不是零报错,而是每次报错都能在 10 秒内让用户知道下一步。