CLI 工具
規則
- Commander.js 用於參數解析 —
.command()、.option()、.argument() 附帶描述
- 互動式提示:
@clack/prompts(現代、美觀)或 inquirer — 當未提供參數時用於使用者輸入
- 旋轉指示器:
ora 用於長時間操作 — 啟動、更新訊息、成功/失敗
- 色彩:
chalk 用於樣式化輸出 — 謹慎使用:紅色表示錯誤,綠色表示成功,黃色表示警告,暗色表示次要資訊
- 設定檔:
cosmiconfig — 自動搜尋 .toolrc、.toolrc.json、tool.config.js、package.json 中的鍵值
- 退出碼:
0 表示成功,1 表示一般錯誤,2 表示用法錯誤 — 務必使用 process.exit(code)
--help 與 --version 旗標:Commander.js 會自動加入這些 — 為每個選項撰寫清晰的描述
- 錯誤處理:在頂層捕捉錯誤,向 stderr 輸出使用者友善訊息,並以代碼 1 退出
- 發佈:
package.json 中的 bin 欄位、#!/usr/bin/env node shebang、"type": "module" 用於 ESM
模式
#!/usr/bin/env node
import { Command } from "commander";
import * as p from "@clack/prompts";
import ora from "ora";
import chalk from "chalk";
const program = new Command()
.name("my-tool")
.description("一個執行有用操作的 CLI")
.version("1.0.0");
program
.command("init")
.description("初始化一個新專案")
.option("-t, --template <name>", "要使用的模板", "default")
.action(async (options) => {
p.intro(chalk.bold("專案設定"));
const name = await p.text({ message: "專案名稱?", placeholder: "my-app" });
if (p.isCancel(name)) { p.cancel("已取消。"); process.exit(0); }
const spinner = ora("正在建立專案...").start();
await createProject(name, options.template);
spinner.succeed(chalk.green("專案已建立!"));
p.outro(`執行 ${chalk.cyan(`cd ${name} && npm install`)}`);
});
program.parse();
避免
- 將錯誤輸出到 stdout — 使用
console.error() 或 process.stderr.write() 輸出錯誤
- 失敗時未帶代碼就退出 — 務必使用
process.exit(1),以便腳本和 CI 能偵測到失敗
- 大量未經格式化的文字 — 使用 chalk 顏色、區塊和空白來提高可讀性
- 要求互動式輸入但沒有提供旗標替代方案 — 務必支援
--flag 覆蓋參數以利 CI/腳本化
- 忘記 shebang
#!/usr/bin/env node — 缺少時,npx 和全域安裝將無法運作