Building a Cross-Platform CLI Tool in TypeScript

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:

TypeScript
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.

Configuring TypeScript

To ensure our TypeScript code compiles correctly, we need to configure our tsconfig.json file. Here’s the configuration I use:

TypeScript
{
  "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:

JSON
"scripts": {
  "build": "tsc"
}

Run the build script to compile your TypeScript code:

ShellScript
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:

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:

ShellScript
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:
ShellScript
  ./dist/my-cli-tool-macos greet Alice
  • On Linux:
ShellScript
  ./dist/my-cli-tool-linux greet Bob
  • On Windows:
ShellScript
  .\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.

Share this:

Leave a Reply