As a developer, creating command-line interface (CLI) tools can greatly enhance productivity and automate repetitive tasks. With TypeScript’s robust type system and modern JavaScript features, we can build reliable and maintainable CLI tools. In this guide, I’ll walk you through the process of building a cross-platform CLI tool in TypeScript and compiling it into binaries for macOS, Windows, and Linux. This approach ensures that your tool can be easily distributed and used across different environments.
Thank me by sharing on Twitter 🙏
Setting Up Your CLI Project
Before we dive into the code, ensure you have a basic TypeScript project set up with the necessary dependencies. You should have typescript
, ts-node
, and @types/node
installed, along with a tsconfig.json
file configured for TypeScript compilation. Additionally, you’ll need commander
for handling command-line arguments and pkg
for compiling your TypeScript code into binaries.
Writing the CLI Script
The heart of our CLI tool lies in the script that handles user input and executes the desired functionality. We’ll use the commander
library to manage command-line arguments and options.
First, create a src/index.ts
file. This file will serve as the entry point for our CLI tool. Here’s a basic example of a CLI tool that greets a user:
import { Command } from 'commander';
const program = new Command();
program
.name('my-cli-tool')
.description('An example CLI tool')
.version('1.0.0');
program
.command('greet <name>')
.description('Greet someone')
.action((name) => {
console.log(`Hello, ${name}!`);
});
program.parse(process.argv);
In this script, we define a CLI tool named my-cli-tool
with a single command greet
that takes a name
parameter and prints a greeting message.
The Nvidia Way: Jensen Huang and the Making of a Tech Giant
$17.50 (as of January 11, 2025 10:31 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)AI Engineering: Building Applications with Foundation Models
$63.58 (as of January 11, 2025 10:31 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)TECKNET Wireless Mouse, 2.4G Ergonomic Optical Mouse, Computer Mouse for Laptop, PC, Computer, Chromebook, Notebook, 6 Buttons, 24 Months Battery Life, 2600 DPI, 5 Adjustment Levels
$8.49 (as of January 9, 2025 10:16 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Configuring TypeScript
To ensure our TypeScript code compiles correctly, we need to configure our tsconfig.json
file. Here’s the configuration I use:
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
This configuration sets the target JavaScript version to ES6 and specifies the output directory for compiled files as dist
. It also ensures strict type-checking and compatibility with CommonJS modules.
Next, add a build script in your package.json
to compile the TypeScript code:
"scripts": {
"build": "tsc"
}
Run the build script to compile your TypeScript code:
npm run build
This command will compile your TypeScript files and place the resulting JavaScript files in the dist
directory.
Preparing for Packaging
Before we package our CLI tool, we need to ensure the bin
property in our package.json
points to the correct entry point. Here’s how to update your package.json
:
{
"name": "my-cli-tool",
"version": "1.0.0",
"description": "An example CLI tool",
"main": "dist/index.js",
"bin": {
"my-cli-tool": "./dist/index.js"
},
"scripts": {
"build": "tsc"
},
"dependencies": {
"commander": "^9.0.0"
},
"devDependencies": {
"pkg": "^5.5.1",
"typescript": "^4.0.0",
"ts-node": "^10.0.0",
"@types/node": "^16.0.0"
}
}
The bin
property points to the compiled index.js
file in the dist
directory, which serves as the entry point for the CLI tool.
Compiling to Binaries
With our project set up and configured, we can now compile our CLI tool into binaries for different platforms using pkg
. Run the following command to generate binaries for macOS, Linux, and Windows:
npx pkg . --out-path dist --targets node18-macos-x64,node18-linux-x64,node18-win-x64
This command will create three binaries in the dist
directory, one for each target platform.
Testing Your CLI Tool
After compiling the binaries, it’s crucial to test them to ensure they work as expected on each platform. Here’s how you can test the binaries:
- On macOS:
./dist/my-cli-tool-macos greet Alice
- On Linux:
./dist/my-cli-tool-linux greet Bob
- On Windows:
.\dist\my-cli-tool-win.exe greet Carol
These commands should print a greeting message for each name provided.
Conclusion
In this guide, we walked through the process of creating a cross-platform CLI tool in TypeScript and compiling it into binaries for macOS, Windows, and Linux. By leveraging the power of TypeScript and the commander
library, we built a simple yet effective CLI tool. Using pkg
, we packaged our tool into standalone binaries that can be easily distributed and used across different environments.
Creating CLI tools in TypeScript not only improves productivity but also ensures that our tools are type-safe and maintainable. With this foundation, you can expand your CLI tool with additional commands and features to suit your needs.