DEV Community

Chris Cook
Chris Cook

Posted on

Creating a TypeScript CLI for Your Monorepo

I like to create local CLIs for my Monorepo to automate tasks like build and deploy. These tasks often require more than just chaining a few commands in an npm script (like rimraf dist && tsc).

Using commander.js and tsx, we can create executable programs written in TypeScript that run from the command line like any other CLI tool.

#!/usr/bin/env -S pnpm tsx
import { Command } from 'commander';

const program = new Command()
  .name('monorepo')
  .description('CLI for Monorepo')
  .version('1.0.0');

program
  .command('build')
  .description('Build the monorepo')
  .action(async () => {
    console.log('Building...');
    // run your build steps ...
  });

program
  .command('deploy')
  .description('Deploy the monorepo')
  .action(async () => {
    console.log('Deploying...');
    // run your deploy steps ...
  });

await program.parseAsync(process.argv);
Enter fullscreen mode Exit fullscreen mode

Save this script as cli (or any name you prefer) in your project root and make it executable with chmod +x cli. You can then run it directly using ./cli:

$ ./cli
Usage: monorepo [options] [command]

CLI for Monorepo

Options:
  -V, --version   output the version number
  -h, --help      display help for command

Commands:
  build           Build the monorepo
  deploy          Deploy the monorepo
  help [command]  display help for command
Enter fullscreen mode Exit fullscreen mode

The magic that allows you to run this without node, npx, or even a .ts extension is in the first line - the shebang:

#!/usr/bin/env -S pnpm tsx
Enter fullscreen mode Exit fullscreen mode

This shebang tells your shell which program should execute this file. Behind the scenes, it translates your ./cli command into pnpm tsx cli. This works with other package managers too - you can use npm or yarn instead of pnpm.

Top comments (8)

Collapse
 
svijaykoushik profile image
Vijay Koushik, S. πŸ‘¨πŸ½β€πŸ’»

I can see myself doing this when build gets complicated. Thanks for the informative post. keep writing

Collapse
 
zirkelc profile image
Chris Cook

I have a built a CLI for building and deploying my Shopify app. It executes multiple CLI commands (vite build, serverless deploy, etc.) via execa.

Maybe I'll make a short follow up post on this :-)

Collapse
 
devmercy profile image
Mercy

This is great @zirkelc, we need more of these.

Collapse
 
zirkelc profile image
Chris Cook

Thanks! :-)

Collapse
 
gunslingor profile image
gunslingor

Lol, lmao, lol. Wow.

Finally a decent build system, and it turns out to be the same approach I was using 20 years ago for software lifestyles but in TS instead of batch which is a nice improvement.

By build system I mean a system for making software life cycles, not a predefined software lifestyle with potential for minimal plug-ins.

After all these years with gradle, maven, ant, Jenkins, and the rest of the junk, I've been missing my batch CLI approach for some time, I hate chaining commands in package.json, you can't even use a space in the command name... how is programming batch INSIDE a json string better than using real batch or maybe this approach?!

Anyway, excited to try this... it has this potential to really bring a monorepo together WITH a seamless platform independent pipeline (ci/cd, sorry, I use the older terms... I see this a lot in web tech, lots of wheel reinventing 30 times, then a decade later people realize, oh, other people had something better 20 years ago... e.g. agile vs. Real project management, build systems vs. Custom life cycles)

Collapse
 
andrii_m_f4650fa6651b5a8 profile image
Andrii M. • Edited

I think best case for this approach are manual tasks that don't need any bash commands triggered. (e.g. tasks you can run with just node.js)

If you need it to run same command in multiple sub-folders in monorepo, I would suggest checking turbo build workspaces. It allows for a similar but a bit easier approach.

And if it's lots of complicated steps usually bash scripts are used they also help automating it for CD/CI pipelines later in the process.

Collapse
 
urbanisierung profile image
Adam

Not only useful for monorepos. Thanks for the blueprint!

Collapse
 
darshkejriwal profile image
Darsh Kejriwal

That's a great thing! Thanks for sharing. Definitely gonna use it in fullstack projects.