Node.js 命令行交互王者:inquirer 模块实战指南

在开发命令行工具时,我们常需要与用户互动 ------ 比如让用户选择模板类型、输入项目名称、确认操作风险等。如果仅靠 process.argv 解析参数,不仅交互体验差,还无法应对复杂的选择场景。而 inquirer 模块的出现,彻底改变了 Node.js 命令行的交互方式,让我们能轻松构建出像 vue-clicreate-react-app 那样流畅的交互式工具。

一、inquirer 模块的核心价值

inquirer 是目前 Node.js 生态中最主流的命令行交互库,每周下载量超 1000 万次,被众多知名工具采用。它的核心优势在于:

  • 丰富的交互类型:支持输入框、单选、多选、确认、列表、密码等 8 种以上交互形式,覆盖几乎所有命令行交互场景。

  • 灵活的配置项:可自定义验证规则、默认值、提示文案,甚至支持异步加载选项列表,满足个性化需求。

  • 优雅的 UI 设计:自带清晰的视觉层级(如选中态、分隔线),支持彩色文字和加载动画,提升用户体验。

  • 良好的兼容性:适配 Windows、macOS、Linux 等主流系统,同时支持 TypeScript 类型提示,降低开发成本。

  • 轻量无冗余:核心依赖仅 2 个,安装包体积不足 50KB,不会给项目带来额外负担。

无论是开发脚手架、工程化脚本,还是运维工具,inquirer 都能让命令行交互从 "功能刚需" 升级为 "体验亮点"。

二、安装与基础使用

1. 安装模块

shell 复制代码
# 使用 npm
npm install inquirer

# 使用 yarn
yarn add inquirer

# TypeScript 项目需额外安装类型定义
npm install -D @types/inquirer

2. 第一个交互式示例

创建 cli.js 文件,实现一个简单的 "项目初始化" 交互流程:

js 复制代码
import inquirer from 'inquirer';

// 定义交互问题列表
const questions = [
  // 1. 输入项目名称(带验证规则)
  {
    type: "input", // 交互类型:输入框
    name: "projectName", // 结果存储的键名
    message: "请输入项目名称:",
    default: "my-project", // 默认值
    validate: (value) => {
      // 验证规则:只能包含小写字母和短横线
      if (/^[a-z-]+$/.test(value)) {
        return true; // 验证通过
      }
      return "项目名称只能包含小写字母和短横线!"; // 验证失败提示
    },
  },
  // 2. 选择项目模板(单选)
  {
    type: "list", // 交互类型:列表(单选)
    name: "template",
    message: "请选择项目模板:",
    choices: [
      // 选项列表
      { name: "Vue 3 模板", value: "vue3" },
      { name: "React 模板", value: "react" },
      { name: "Node.js 后端模板", value: "node" },
    ],
  },
  // 3. 确认是否初始化 Git(确认框)
  {
    type: "confirm", // 交互类型:确认框(是/否)
    name: "initGit",
    message: "是否初始化 Git 仓库?",
    default: true, // 默认值:是
  },
];

// 执行交互并处理结果
inquirer.prompt(questions).then((answers) => {
  console.log("n===== 项目配置结果 =====");
  console.log(`项目名称:${answers.projectName}`);
  console.log(`选择模板:${answers.template}`);
  console.log(`初始化 Git:${answers.initGit ? "是" : "否"}`);
  console.log("n开始创建项目...");
});

运行脚本,即可看到交互式流程:

shell 复制代码
node cli.js

交互过程示例:

shell 复制代码
? 请输入项目名称: my-vue-app

? 请选择项目模板: Vue 3 模板

? 是否初始化 Git 仓库? Yes

===== 项目配置结果 =====

项目名称:my-vue-app

选择模板:vue3

初始化 Git:是

开始创建项目...

三、核心交互类型与实战场景

inquirer 支持 10+ 种交互类型,以下是最常用的 6 种及对应的实战场景:

1. 输入框(input):处理文本输入

适用于需要用户输入自定义内容的场景(如项目名称、邮箱、URL):

js 复制代码
{
 type: 'input',
 name: 'author',
 message: '请输入作者名称:',
 default: '匿名开发者',
 // 输入时的提示(可选)
 transformer: (value) => `当前输入:${value}`,
 // 异步验证(如检查邮箱是否已注册)
 validate: async (value) => {
   // 模拟接口请求
   await new Promise(resolve => setTimeout(resolve, 500));
   if (value.includes('@')) {
     return true;
   }
   return '请输入有效的邮箱地址!';
 }
}

2. 密码框(password):处理敏感信息

输入内容会被隐藏,适用于密码、密钥等敏感信息:

js 复制代码
{
 type: 'password',
 name: 'dbPassword',
 message: '请输入数据库密码:',
 // 可选:用 * 显示输入长度(默认完全隐藏)
 mask: '*'
}

3. 单选列表(list):二选一或多选一

选项固定且需用户明确选择,适用于模板类型、环境选择等场景(如前文示例)。

4. 多选列表(checkbox):选择多个选项

支持用户勾选多个选项,适用于依赖安装、功能开启等场景:

js 复制代码
{
 type: 'checkbox',
 name: 'features',
 message: '请选择需要集成的功能:',
 choices: [
   { name: 'TypeScript', value: 'ts', checked: true }, // 默认勾选
   { name: 'ESLint', value: 'eslint' },
   { name: 'Prettier', value: 'prettier' },
   { name: '单元测试', value: 'test' }
 ],
 // 限制最少选择 1 个
 validate: (selected) => {
   if (selected.length >= 1) {
     return true;
   }
   return '至少选择一个功能!';
 }
}

交互结果会以数组形式返回,例如:features: ['ts', 'eslint']

5. 下拉选择(rawlist):简化版单选

list 类似,但选项以编号展示,用户输入编号选择(更适合选项较多的场景):

js 复制代码
{
 type: 'rawlist',
 name: 'framework',
 message: '请选择前端框架(输入编号):',
 choices: ['Vue', 'React', 'Angular', 'Svelte']
}

交互示例:

shell 复制代码
? 请选择前端框架(输入编号):

 1) Vue

 2) React

 3) Angular

 4) Svelte

> 2

6. 自动补全(autocomplete):智能输入提示

适用于选项较多且用户可能记不清完整名称的场景(如选择已有项目),需配合 inquirer-autocomplete-prompt 插件:

shell 复制代码
# 安装插件

npm install inquirer-autocomplete-prompt

对应版本:

json 复制代码
"inquirer": "^9.1.0",
"inquirer-autocomplete-prompt": "^3.0.1"
js 复制代码
import inquirer from 'inquirer';
import inquirerPrompt from 'inquirer-autocomplete-prompt';

// 注册自动补全插件
inquirer.registerPrompt('autocomplete', inquirerPrompt);

// 模拟异步获取项目列表(如从数据库或接口获取)
const searchProjects = async (answersSoFarm, input = "") => {
  const allProjects = [
    "project-admin",
    "project-user",
    "project-blog",
    "project-api",
  ];

  // 根据用户输入过滤结果
  return allProjects.filter((project) => project.includes(input));
};

const questions = [
  {
    type: "autocomplete",
    name: "targetProject",
    message: "请选择要部署的项目(支持模糊搜索):",
    source: searchProjects, // 异步获取选项的函数
  },
];

inquirer.prompt(questions).then((answers) => {
  console.log(`已选择部署项目:${answers.targetProject}`);
});

四、进阶技巧:提升交互体验

1. 条件性显示问题

根据用户之前的选择,动态显示或隐藏后续问题(如选择 "Vue 模板" 后才显示 Vue 版本选择):

js 复制代码
const questions = [
  {
    type: "list",
    name: "template",
    message: "选择模板:",
    choices: ["vue", "react", "node"],
  },
  // 只有当 template 为 vue 时才显示该问题
  {
    type: "list",
    name: "vueVersion",
    message: "选择 Vue 版本:",
    choices: ["Vue 2", "Vue 3"],
    when: (answers) => answers.template === "vue", // 条件判断
  },
];

2. 结合其他工具增强体验

搭配 chalk(彩色文字)、ora(加载动画)等工具,让交互流程更流畅:

shell 复制代码
# 安装依赖
npm install chalk ora
js 复制代码
import inquirer from 'inquirer';
import chalk from 'chalk'
import ora from 'ora'

const questions = [
  {
    type: "confirm",
    name: "deploy",
    message: chalk.yellow("是否确认部署到生产环境?(此操作不可逆)"),
    default: false,
  },
];

inquirer.prompt(questions).then(async (answers) => {
  if (answers.deploy) {
    // 显示加载动画
    const spinner = ora("正在部署...").start();
    // 模拟部署耗时
    await new Promise((resolve) => setTimeout(resolve, 2000));
    spinner.succeed(chalk.green("部署成功!"));
  } else {
    console.log(chalk.blue("已取消部署"));
  }
});

五、实战案例:构建简易脚手架

结合 inquirerfs-extra(文件操作工具),实现一个 "创建组件" 的脚手架:

shell 复制代码
# 安装依赖
npm install inquirer fs-extra path
js 复制代码
import inquirer from 'inquirer';

import fs from 'fs-extra';
import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 组件模板内容
const componentTemplate = (name) => `
<template>
 <div class="${name}">
   <!-- ${name} 组件 -->
 </div>
</template>

<script setup>
// 组件逻辑
</script>

<style scoped>
.${name} {
 /* 样式 */
}
</style>
`;

// 交互流程
const createComponent = async () => {
  const questions = [
    {
      type: "input",
      name: "componentName",
      message: "请输入组件名称( PascalCase 格式):",
      default: "MyComponent",
      validate: (value) => {
        if (/^[A-Z][a-zA-Z0-9]*$/.test(value)) {
          return true;
        }
        return "请输入 PascalCase 格式的名称(如 Button、UserCard)";
      },
    },
    {
      type: "list",
      name: "componentType",
      message: "选择组件类型:",
      choices: ["页面组件", "公共组件"],
      filter: (value) => (value === "页面组件" ? "views" : "components"), // 转换值
    },
  ];

  // 执行交互
  const answers = await inquirer.prompt(questions);

  const { componentName, componentType } = answers;

  const dir = path.resolve(
    __dirname,
    `./src/${componentType}`
  );

  // 组件保存路径
  const componentPath = path.join(
    dir,
    `${componentName}.vue`
  );

  await fs.ensureDir(dir);

  // 检查组件是否已存在
  if (await fs.pathExists(componentPath)) {
    console.log(`❌ 组件 ${componentName} 已存在`);
    return;
  }

  // 写入组件文件
  await fs.writeFile(componentPath, componentTemplate(componentName));
  console.log(`✅ 组件 ${componentName} 创建成功,路径:${componentPath}`);
};

// 启动脚手架
createComponent();


运行脚本后,只需按提示输入信息,即可快速创建符合规范的 Vue 组件,大幅提升开发效率。

六、总结

inquirer 以其丰富的交互类型、灵活的配置能力和优雅的 UI 设计,成为 Node.js 命令行工具的 "交互标配"。它不仅能满足基础的输入、选择需求,还能通过进阶技巧实现个性化、智能化的交互流程,让命令行工具从 "能用" 变为 "好用"。

如果你正在开发脚手架、工程化脚本或任何需要用户交互的命令行工具,inquirer 绝对是值得优先选择的工具。尝试用它重构你的脚本,你会发现命令行交互也能带来出色的用户体验!

欢迎在留言区分享你用 inquirer 开发的工具,或提出使用中遇到的问题,我们一起探讨更多交互技巧!

相关推荐
Java微观世界8 小时前
static在Java中到底怎么用?5分钟搞懂变量、方法、代码块与内部类
后端·面试
他日若遂凌云志8 小时前
深度剖析 Fantasy 框架的多协议网络通信(一):TCP 可靠传输与连接管控
后端
开心就好20258 小时前
Fiddler 抓不到包怎么办?从排查到替代方案的全流程指南
后端
知其然亦知其所以然8 小时前
面试官最爱问的坑:MySQL 中 FLOAT 和 DOUBLE 你真懂吗?
后端·mysql·面试
雨中散步撒哈拉8 小时前
12、做中学 | 初一上期 Golang函数 包 异常
开发语言·后端·golang
AAA修煤气灶刘哥8 小时前
从全表扫描到 0.1 秒查询:数据库索引吃透这篇,面试不慌
java·数据库·后端
笃行3509 小时前
打造智能写作工作流:n8n + 蓝耘MaaS平台完整实战指南
后端
Cdlblbq9 小时前
使用原生excel方式导入excel
node.js
悟空呀9 小时前
Channel 异步写入的隐形陷阱
后端