在开发命令行工具时,我们常需要与用户互动 ------ 比如让用户选择模板类型、输入项目名称、确认操作风险等。如果仅靠 process.argv
解析参数,不仅交互体验差,还无法应对复杂的选择场景。而 inquirer
模块的出现,彻底改变了 Node.js 命令行的交互方式,让我们能轻松构建出像 vue-cli
、create-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("已取消部署"));
}
});
五、实战案例:构建简易脚手架
结合 inquirer
和 fs-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
开发的工具,或提出使用中遇到的问题,我们一起探讨更多交互技巧!