🔍搜索⌘K

Node.js 命令行脚本开发:4 个必备工具包

概述

用 Node.js 写命令行脚本(比如项目初始化工具、批量处理脚本、CLI 工具)时,光靠原生的 process.argv 解析参数、console.log 输出内容,会撞上三大痛点:

  1. 参数解析繁琐:手动处理 —version、—help 或者自定义命令(比如 init/build),得写一大堆判断逻辑;
  2. 交互体验差:没法轻松搞出「输入框、单选 / 多选」这类交互,用户操作门槛高;
  3. 视觉反馈弱:输出单调没样式,耗时的活也没个加载提示,用户根本不知道脚本是不是卡住了。

这篇要推荐的 Commander、Inquirer、Chalk、Ora 四个工具包,正好能对症下药——它们是 Node.js 命令行开发的「黄金组合」,轻量、好用、生态也成熟,从「参数解析」到「交互设计」再到「视觉优化」全流程覆盖,让你很快就能写出专业级的 CLI 脚本。

一、1. Commander:命令行参数解析 “神器”

Commander 是 Node.js 生态里最流行的命令行参数解析库,灵感来自 Ruby 的 commander,能帮你快速定义「命令、选项、参数」,自动生成 —help 文档和 —version 功能,不用自己手写那堆复杂的参数逻辑。

它主要能帮你干这些事:

  • 支持自定义命令(比如 my-cli init、my-cli build);
  • 自动解析短选项(-v)和长选项(—version);
  • 生成标准化的帮助文档(—help);
  • 支持参数校验、默认值设置、必填项声明。

实战示例(基础用法)

步骤 1:安装

npm install commander  # 或 yarn add commander

步骤 2:编写脚本(cli.js)

#!/usr/bin/env node
const { program } = require("commander");

// 1. 设置脚本版本(支持 -v/--version 查看)
program.version("1.0.0", "-v, --version", "查看脚本版本");

// 2. 定义全局选项(所有命令可共用)
program.option("-d, --debug", "开启调试模式", false); // 第三个参数是默认值

// 3. 定义子命令:init(用于初始化项目)
program
  .command("init <project-name>") // <project-name> 是必填参数
  .description("初始化一个新的项目")
  .option("-t, --template <template-name>", "指定项目模板(vue/react)", "vue") // 可选选项,默认 vue
  .action((projectName, options) => {
    // 命令执行逻辑
    console.log(`正在初始化项目:${projectName}`);
    console.log(`使用模板:${options.template}`);
    console.log(`调试模式:${program.opts().debug ? "开启" : "关闭"}`);
    // 此处可添加创建目录、下载模板等逻辑
  });

// 4. 解析命令行参数(必须放在最后)
program.parse(process.argv);

步骤 3:运行脚本

# 查看版本
node cli.js -v  # 输出:1.0.0

# 查看帮助(自动生成)
node cli.js --help
# 输出会包含版本、全局选项、子命令列表及描述

# 执行 init 命令(使用默认模板)
node cli.js init my-project

# 执行 init 命令(指定 react 模板 + 开启调试)
node cli.js init my-project -t react --debug

为什么推荐?

  • 零学习成本:API 设计直观,30 分钟就能上手;
  • 生态兼容:跟 package.json 的 bin 字段完美配合(能把脚本注册成全局命令);
  • 标准化输出:自动生成的帮助文档和版本信息,符合用户对 CLI 工具的使用习惯。

二、2. Inquirer:交互式命令行 “引擎”

Inquirer 是个搞「问答式交互」的工具库,支持输入框、单选、多选、列表、密码输入这些交互形式,让脚本从「被动等参数」变成「主动引导用户操作」,用户体验一下子就上来了。

它主要能做这些:

  • 支持 7 种交互类型:input(输入框)、list(单选列表)、checkbox(多选)、password(密码)等;
  • 支持输入验证(比如校验邮箱格式、必填项);
  • 支持异步交互(比如根据前一个选项动态生成后一个选项);
  • 输出格式整洁,跟命令行环境很搭。

实战示例(基础用法)

步骤 1:安装

npm install inquirer  # 或 yarn add inquirer

步骤 2:编写脚本(interactive.js)

#!/usr/bin/env node
const inquirer = require("inquirer");

// 定义交互问题(数组形式,每个元素是一个问题配置)
const questions = [
  // 1. 输入框:获取用户名
  {
    type: "input",
    name: "username", // 存储结果的键名
    message: "请输入你的用户名:",
    default: "guest", // 默认值
    validate: (value) => {
      // 输入验证
      if (value.length < 3) {
        return "用户名至少 3 个字符"; // 验证失败提示
      }
      return true; // 验证通过
    },
  },
  // 2. 密码输入:获取密码(输入内容隐藏)
  {
    type: "password",
    name: "password",
    message: "请输入你的密码:",
    mask: "*", // 用 * 隐藏输入内容
  },
  // 3. 单选列表:选择项目类型
  {
    type: "list",
    name: "projectType",
    message: "请选择项目类型:",
    choices: [
      // 选项列表
      { name: "Vue 项目", value: "vue" },
      { name: "React 项目", value: "react" },
      { name: "Node.js 后端项目", value: "node" },
    ],
    default: "vue",
  },
  // 4. 多选:选择需要安装的依赖
  {
    type: "checkbox",
    name: "dependencies",
    message: "请选择需要安装的依赖:",
    choices: ["axios", "lodash", "moment", "express"],
    default: ["axios"], // 默认选中的选项
  },
];

// 执行交互并处理结果
inquirer.prompt(questions).then((answers) => {
  console.log("\n=== 你选择的配置 ===");
  console.log(`用户名:${answers.username}`);
  console.log(`项目类型:${answers.projectType}`);
  console.log(`需要安装的依赖:${answers.dependencies.join(", ")}`);
  // 此处可添加根据配置创建项目、安装依赖的逻辑
});

步骤 3:运行脚本

node interactive.js

跑起来后会依次蹦出输入框、密码框、单选列表、多选列表,用户操作完,脚本就把所有选择结果打印出来。

适用场景

  • 项目初始化工具(比如 create-react-app 里的交互逻辑);
  • 配置生成脚本(比如让用户选环境、功能模块,自动生成配置文件);
  • 批量操作确认(比如删多个文件前,让用户确认要不要继续)。

三、3. Chalk:命令行文本 “调色盘”

Chalk 是给命令行输出文本加颜色和样式(比如红色错误、绿色成功、加粗标题)的库,解决原生 console.log 输出太单调的问题,让关键信息更扎眼,脚本可读性也更好。

它主要能帮你:

  • 支持 1600 万种颜色(真彩色)和 256 色;
  • 支持文本样式:加粗、斜体、下划线、删除线、背景色;
  • 支持链式调用(比如 chalk.red.bold(‘文本’));
  • 轻量无依赖,性能优异。

实战示例(基础用法)

步骤 1:安装

npm install chalk  # 或 yarn add chalk

步骤 2:编写脚本(colored-log.js)

#!/usr/bin/env node
const chalk = require("chalk");

// 1. 基础颜色:红、绿、蓝、黄等
console.log(chalk.red("❌ 错误:文件不存在"));
console.log(chalk.green("✅ 成功:操作完成"));
console.log(chalk.blue("ℹ️  信息:正在下载模板"));
console.log(chalk.yellow("⚠️  警告:版本过低"));

// 2. 文本样式:加粗、斜体、下划线
console.log("\n" + chalk.bold("=== 加粗标题 ==="));
console.log(chalk.italic("这是斜体文本"));
console.log(chalk.underline("这是下划线文本"));

// 3. 链式调用:颜色 + 样式 + 背景色
console.log("\n" + chalk.bgBlue.white.bold("  重要通知  "));
console.log(chalk.red.bold.underline("请立即更新到最新版本"));

// 4. 模板字符串(ES6 语法,更简洁)
const username = "张三";
console.log("\n" + `欢迎你,${chalk.green.bold(username)}!`);
console.log(`当前环境:${chalk.yellow(process.env.NODE_ENV || "development")}`);

步骤 3:运行脚本

node colored-log.js

跑起来就能看到不同颜色、不同样式的文本输出,错误信息、成功信息、标题这些一眼就分得出。

进阶技巧

  • 条件样式:根据状态动态切换颜色(比如 chalkstatus ? ‘green’ : ‘red’);
  • 自定义颜色:用 chalk.hex(‘#FF5733’)(‘自定义颜色文本’) 或 chalk.rgb(255, 87, 51)(‘文本’);
  • 禁用颜色:在非交互式终端(比如日志文件)里,可以用 chalk.level = 0 把颜色输出关掉。

四、4. Ora:命令行加载 “动画师”

Ora 能在命令行里显示加载动画和进度条,解决「耗时操作没反馈」的问题(比如下载文件、处理数据时,用户不知道脚本是不是卡死了),让等待体验好不少。

它主要能做这些:

  • 支持 50+ 种加载动画(比如旋转圆圈、进度条、脉冲等);
  • 支持加载状态切换:开始、成功、失败、警告;
  • 支持自定义动画文本和图标;
  • 轻量无依赖,能适配不同终端环境。

实战示例(基础用法)

步骤 1:安装

npm install ora  # 或 yarn add ora

步骤 2:编写脚本(loading.js)

#!/usr/bin/env node
const ora = require("ora");
const fs = require("fs/promises"); // 用 promise 版 fs 模拟耗时操作

// 模拟耗时操作(如文件下载、数据处理)
async function mockLongTask(taskName, duration) {
  // 1. 创建加载动画,设置文本
  const spinner = ora(`正在${taskName}...`).start();

  try {
    // 2. 执行耗时操作(此处用 setTimeout 模拟)
    await new Promise((resolve) => setTimeout(resolve, duration));

    // 3. 操作成功:切换动画为成功状态
    spinner.succeed(`${taskName}完成!`);
  } catch (error) {
    // 4. 操作失败:切换动画为失败状态,显示错误信息
    spinner.fail(`${taskName}失败:${error.message}`);
  }
}

// 批量执行耗时操作
async function runTasks() {
  await mockLongTask("下载模板", 2000); // 模拟 2 秒下载
  await mockLongTask("创建项目目录", 1500); // 模拟 1.5 秒创建目录
  await mockLongTask("安装依赖", 3000); // 模拟 3 秒安装依赖

  // 额外示例:自定义动画样式(进度条)
  const progressSpinner = ora({
    text: "处理数据中...",
    spinner: "line", // 进度条样式的动画
  }).start();

  // 模拟进度更新
  for (let i = 0; i <= 100; i += 10) {
    await new Promise((resolve) => setTimeout(resolve, 300));
    progressSpinner.text = `处理数据中... ${i}%`;
  }
  progressSpinner.succeed("数据处理完成!");
}

// 启动任务
runTasks();

步骤 3:运行脚本

node loading.js

跑起来会看到:

  1. 旋转动画 + 文本提示(比如「正在下载模板…」);
  2. 操作完成后,动画切换成绿色对勾 + 成功文本;
  3. 最后还有个进度条动画,实时更新处理进度。

适用场景

  • 网络请求(比如下载文件、调 API);
  • 磁盘操作(比如批量复制文件、压缩解压);
  • 数据处理(比如解析大文件、批量转换格式)。

五、组合实战:打造一个小型 CLI 工具

把上面四个工具包揉一起,很快就能搞出一个「项目初始化 CLI」,完整流程是这样的:

  1. 用 Commander 解析 init 命令和全局选项;
  2. 用 Inquirer 引导用户输入项目信息、选模板;
  3. 用 Ora 显示模板下载、目录创建的加载动画;
  4. 用 Chalk 输出彩色的成功 / 错误提示。

核心代码片段(my-cli.js)

#!/usr/bin/env node
const { program } = require("commander");
const inquirer = require("inquirer");
const chalk = require("chalk");
const ora = require("ora");
const fs = require("fs/promises");
const path = require("path");

// 1. Commander 配置
program
  .version("1.0.0", "-v, --version")
  .command("init <project-name>")
  .description("初始化 Node.js 项目")
  .action(async (projectName) => {
    // 2. Inquirer 交互
    const answers = await inquirer.prompt([
      {
        type: "list",
        name: "template",
        message: "选择项目模板:",
        choices: ["basic", "express", "koa"],
        default: "basic",
      },
      {
        type: "confirm",
        name: "installDeps",
        message: "是否自动安装依赖?",
        default: true,
      },
    ]);

    const projectPath = path.resolve(process.cwd(), projectName);
    const spinner = ora();

    try {
      // 3. Ora 加载动画 + 磁盘操作
      spinner.start(`正在创建项目目录:${projectName}`);
      await fs.mkdir(projectPath, { recursive: true });
      spinner.succeed("项目目录创建完成");

      spinner.start(`正在下载 ${answers.template} 模板`);
      // 此处可替换为实际的模板下载逻辑(如 git clone)
      await new Promise((resolve) => setTimeout(resolve, 2000));
      spinner.succeed(`${answers.template} 模板下载完成`);

      // 4. Chalk 彩色输出结果
      console.log("\n" + chalk.bold.green("=== 项目初始化完成 ==="));
      console.log(`项目路径:${chalk.blue(projectPath)}`);
      console.log(`模板类型:${chalk.yellow(answers.template)}`);
      console.log("\n下一步操作:");
      console.log(`  cd ${projectName}`);
      if (!answers.installDeps) {
        console.log("  npm install");
      }
      console.log("  npm run dev");
    } catch (error) {
      spinner.fail("项目初始化失败");
      console.log(chalk.red(`错误信息:${error.message}`));
    }
  });

program.parse(process.argv);

运行效果

# 全局注册脚本(需在 package.json 中配置 "bin": {"my-cli": "./my-cli.js"})
npm link

# 执行初始化命令
my-cli init my-node-project

跑起来会依次经历「交互选择 → 加载动画 → 彩色结果输出」,体验完全不输成熟的 CLI 工具(比如 create-vite)。

六、总结:工具包选择建议与扩展方向

工具包核心作用学习成本适用场景
Commander解析命令、选项、参数低(30 分钟上手)所有需要接收参数的 CLI 脚本(如 init/build 命令)
Inquirer实现交互式问答中(1 小时掌握核心)需要用户输入 / 选择的场景(项目配置、批量操作确认)
Chalk文本颜色与样式美化低(10 分钟上手)所有需要区分日志类型的脚本(错误、成功、警告提示)
Ora加载动画与进度反馈低(15 分钟上手)耗时操作场景(文件下载、依赖安装、数据处理)

1. 工具包搭配原则

  • 基础组合:任何 CLI 脚本都建议配 Commander + Chalk——前者管参数解析,后者管日志可读性,属于「保底配置」;
  • 交互场景:要用户输入就叠 Inquirer(比如项目初始化工具);
  • 耗时操作:有超过 1 秒的任务就叠 Ora(比如文件处理、网络请求);
  • 全量组合:复杂 CLI 工具(比如脚手架)建议四个包一起上,覆盖「参数 → 交互 → 反馈 → 美化」全流程(参考 create-vite、vue-cli 的设计)。

2. 扩展工具推荐(进阶需求)

要是脚本需要更牛的能力,可以再搭配下面这些工具包:

  • shelljs/execa:执行系统命令(比如 git clone、npm install),解决 Node.js 原生 child_process 语法繁琐的问题;

示例:用 execa 执行 npm install 并实时输出日志:

const { execa } = require("execa");
await execa("npm", ["install"], { cwd: projectPath, stdio: "inherit" });
  • fs-extra:增强版文件操作库,在原生 fs 基础上补了「递归创建目录」「复制文件夹」「文件存在判断」这些常用功能,免得重复造轮子;

示例:递归复制模板文件:

const fse = require("fs-extra");
await fse.copy("./templates/basic", projectPath);
  • figlet:生成 ASCII 艺术字标题(比如脚本启动时显示个大标题),提升 CLI 的视觉辨识度; 示例:
const figlet = require("figlet");
console.log(chalk.green(figlet.textSync("My CLI")));
  • yargs:跟 Commander 类似的参数解析库,支持更复杂的参数嵌套和自定义帮助文档,适合大型 CLI 工具(比如 webpack-cli 用的就是 yargs)。

3. 发布与使用:将脚本变成全局 CLI 工具

开发完可以把脚本发布到 npm 仓库,让别人用 npm install -g 全局安装使用,关键步骤如下:

  1. 配置 package.json:
{
  "name": "my-node-cli", // CLI 工具名称(发布到 npm 需唯一)
  "version": "1.0.0",
  "bin": {
    "my-cli": "./my-cli.js" // 注册全局命令:my-cli → 脚本路径
  },
  "dependencies": {
    "commander": "^12.0.0",
    "inquirer": "^9.2.16",
    "chalk": "^5.3.0",
    "ora": "^8.0.1"
  }
}
  1. 本地测试:

先用 npm link 把脚本注册成本地全局命令,测测能不能正常跑:

npm link  # 注册全局命令
my-cli -v  # 测试版本命令(应输出 1.0.0)
my-cli init test-project  # 测试 init 命令
  1. 发布到 npm(可选):

要是想公开分享,跑 npm publish 发到 npm 仓库(得先注册 npm 账号并登录),别人就能用下面命令装来用:

npm install -g my-node-cli  # 全局安装
my-cli init new-project     # 使用 CLI 工具

七、结语:用工具包提升开发效率

Node.js 命令行开发的核心不是「重复造轮子」,而是用成熟的工具包快速把功能实现——Commander 帮你搞定参数解析,Inquirer 帮你优化交互,Chalk 和 Ora 帮你提升视觉体验,四个工具包各管一摊,却能起到 1+1+1+1>4 的效果。

不管是写个人用的小脚本(比如批量处理文件),还是团队协作的脚手架(比如项目初始化工具),掌握这些工具包都能让你事半功倍。建议从「实现一个简单的项目初始化脚本」开始练,在开发里慢慢熟悉每个工具的用法,逐步打磨出专业级的 CLI 工具。