🛠 用 Node.js 和 commander 快速搭建一个 CLI 工具骨架(gix 实战)

🛠 用 Node.js 和 commander 快速搭建一个 CLI 工具骨架(gix 实战)

在上一篇中,我们聊了聊为什么我要开发一个 Git CLI 工具 ------ gix,解决我日常开发中繁琐重复的 Git 操作。

这篇文章,我们正式开工,从 0 到 1 搭建一个 CLI 工具的基础骨架,包含命令解析、参数传递、交互式输入等核心功能。


🧰 技术选型

工具 用途
Node.js 编写 CLI 工具的基础平台
TypeScript 类型安全、增强开发体验
commander 命令行参数解析
prompts 交互式输入(比 inquirer 更轻量)
chalk 控制终端输出样式
execa 执行 Git 命令

📁 项目初始化

我们用 pnpm 创建项目:

csharp 复制代码
pnpm init

安装依赖:

sql 复制代码
pnpm add commander prompts chalk execa
pnpm add -D typescript tsx @types/node

创建 tsconfig.json:

json 复制代码
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "outDir": "dist",
    "strict": true
  },
  "include": ["src"]
}

🧱 文件结构

bash 复制代码
/packages/cli
  ├── src
  │   ├── index.ts         # 入口文件
  │   ├── commands
  │   │   ├── squash.ts    # squash 命令逻辑
  │   │   └── merge.ts     # merge 命令逻辑
  │   └── utils
  │       └── git.ts       # Git 命令封装
  ├── package.json
  └── tsconfig.json

🚪 Step 1:配置命令行入口

在 src/index.ts 中配置 CLI 主入口:

javascript 复制代码
#!/usr/bin/env node

import { Command } from 'commander'
import { runSquash } from './commands/squash'
import { runMerge } from './commands/merge'

const program = new Command()

program.name('gix').description('Git 扩展工具集').version('0.0.1')

program
  .command('squash')
  .description('合并最近的多次提交')
  .option('-n, --count <number>', '合并次数', '2')
  .option('--all', '合并所有提交')
  .action(runSquash)

program
  .command('merge')
  .description('交互式合并两个 commit')
  .option('-f, --from <hash>', '起始 commit')
  .option('-t, --to <hash>', '结束 commit')
  .option('-m, --message <msg>', '合并后的 commit 信息')
  .action(runMerge)

program.parse()

在 package.json 中加入:

json 复制代码
"bin": {
  "gix": "dist/index.js"
}

然后加上执行权限:

bash 复制代码
chmod +x dist/index.js

✨ Step 2:实现 squash 命令逻辑

src/commands/squash.ts

typescript 复制代码
import prompts from 'prompts'
import { execGit } from '../utils/git'
import chalk from 'chalk'

export async function runSquash(opts: { count: string; all?: boolean }) {
  const count = opts.all ? 'HEAD~$(git rev-list --count HEAD)' : `HEAD~${opts.count}`

  const { message } = await prompts({
    type: 'text',
    name: 'message',
    message: '请输入新的 commit 信息:'
  })

  if (!message) {
    console.log(chalk.red('❌ commit 信息不能为空'))
    return
  }

  await execGit(`reset --soft ${count}`)
  await execGit(`commit -m "${message}" --no-verify`)

  console.log(chalk.green('🎉 squash 成功完成!'))
}

🔧 Step 3:封装 Git 命令工具函数

src/utils/git.ts

javascript 复制代码
import { execa } from 'execa'

export async function execGit(cmd: string) {
  const [cmdName, ...args] = cmd.split(' ')
  await execa(cmdName, args, { stdio: 'inherit' })
}

✅ 试运行

bash 复制代码
pnpm build
pnpm link
gix squash -n 2

输出:

sql 复制代码
? 请输入新的 commit 信息:feat: 优化用户界面逻辑
🎉 squash 成功完成!

💡 小结

至此,我们完成了:

  • 初始化 CLI 工具项目结构

  • 配置 commander 命令解析

  • 支持交互式输入(prompts)

  • 执行 Git 命令(execa)

gix 的核心命令正在一步步搭建中 🚀


🔮 下一篇预告

下一篇我会分享如何构建更复杂的交互命令(如 gix merge),支持选择 commit、填写信息、自动推送,并通过 prompts 提升使用体验。

欢迎点赞 + 收藏 + 评论支持我继续更系列文章!

相关推荐
程序媛学姐4 分钟前
SpringBoot Actuator健康检查:自定义HealthIndicator
java·spring boot·后端
程序媛学姐16 分钟前
SpringBoot Actuator指标收集:Micrometer与Prometheus集成
spring boot·后端·prometheus
欲儿26 分钟前
RabbitMQ原理及代码示例
java·spring boot·后端·rabbitmq
林 子28 分钟前
Spring Boot自动装配原理(源码详细剖析!)
spring boot·后端
编程轨迹29 分钟前
使用 Spring 和 Redis 创建处理敏感数据的服务
后端
iOS阿玮33 分钟前
待业的两个月,让我觉得独立开发者才是职场的归宿。
前端·app
八了个戒42 分钟前
「数据可视化 D3系列」入门第六章:比例尺的使用
前端·javascript·信息可视化·数据可视化·canvas
少糖研究所1 小时前
ACPA算法详解
前端
Mores1 小时前
开源 | ImageMinify:轻量级智能图片压缩工具,为你的项目瘦身加速
前端
未完结小说1 小时前
服务注册与发现(nacos)
后端