Building a Custom CLI Tool with Node.js and TypeScript
Introduction
A CLI tool enhances developer workflows. This guide walks through building a TypeScript-based CLI with commands, options, and plugins.
Prerequisites
- Node.js >=16
- TypeScript
- npm or pnpm
Step 1: Initialize Project
mkdir my-cli
cd my-cli
pnpm init -y
pnpm add -D typescript @types/node ts-node
Create tsconfig.json
:
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"rootDir": "src",
"outDir": "dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
Step 2: Install CLI Libraries
pnpm add commander chalk
Step 3: Implement CLI Entrypoint
Create src/index.ts
:
#!/usr/bin/env node
import { Command } from 'commander';
import chalk from 'chalk';
const program = new Command();
program
.name('my-cli')
.description('My custom CLI tool')
.version('1.0.0');
program
.command('greet')
.description('Print greeting')
.option('-n, --name <name>', 'Name to greet', 'World')
.action((options) => {
console.log(chalk.green(`Hello, ${options.name}!`));
});
program.parse(process.argv);
Make it executable:
chmod +x src/index.ts
Add to package.json
:
"bin": { "my-cli": "dist/index.js" }
Step 4: Build and Publish
pnpm tsc
pnpm pack
# or publish to npm
npm publish
Step 5: Plugin Support
Support external plugins:
program
.command('run <plugin>')
.description('Run a plugin')
.action(async (pluginName) => {
try {
const plugin = require(pluginName);
await plugin.run();
} catch (err) {
console.error(chalk.red('Plugin not found'));
}
});
Step 6: Comprehensive Help
Ensure commands show help:
my-cli --help
git my-cli greet --help
Summary
This guide covers creating a TypeScript CLI with argument parsing via Commander, colored output with Chalk, plugin extensibility, and packaging for npm.