cac — Command And Conquer, a JavaScript library for building CLI apps.

Ramu NarasingaRamu Narasinga
2 min read

In this article, we will review cac — command and conquer, a JavaScript library for building cli apps.

  1. What is cac package?

  2. cac usage in Tsup.

What is cac package?

Command and conquer is a JavaScript library for building cli apps.

Features

  • Super light-weight: No dependency, just a single file.

  • Easy to learn. There’re only 4 APIs you need to learn for building simple CLIs: cli.option cli.version cli.help cli.parse.

  • Yet so powerful. Enable features like default command, git-like subcommands, validation for required arguments and options, variadic arguments, dot-nested options, automated help message generation and so on.

  • Developer friendly. Written in TypeScript.

learn more about cac package in the documentation.

Usage

Simple Parsing

Use CAC as simple argument parser:

// examples/basic-usage.js
const cli = require('cac')()

cli.option('--type <type>', 'Choose a project type', {
  default: 'node',
})

const parsed = cli.parse()

console.log(JSON.stringify(parsed, null, 2))

This example is picked from documentation.

cac usage in Tsup

  1. In a file named cli-main.ts in Tsup source code, cac is imported as shown below:
import { cac } from 'cac'

2. At line 12 in cli-main.ts, cac is initialised as shown below:

 const cli = cac('tsup')

3. From line 18 to 102 options are configured. As you can see, there are lot of options available in this Tsup library.

 .option('--entry.* <file>', 'Use a key-value pair as entry files')
    .option('-d, --out-dir <dir>', 'Output directory', { default: 'dist' })
    .option('--format <format>', 'Bundle format, "cjs", "iife", "esm"', {
      default: 'cjs',
    })
    .option('--minify [terser]', 'Minify bundle')
    .option('--minify-whitespace', 'Minify whitespace')
    .option('--minify-identifiers', 'Minify identifiers')
    .option('--minify-syntax', 'Minify syntax')
    .option(
      '--keep-names',
      'Keep original function and class names in minified code',
    )

4. Below is the command configuration:

  .command('[...files]', 'Bundle files', {
      ignoreOptionDefaultValue: true,
    })

5. In the actions, all the arguments that you have passed are accessible via flags variable. options is updated with these flags as shown below

  .action(async (files: string[], flags) => {
      const { build } = await import('.')
      Object.assign(options, {
        ...flags,
      })

Most importantly, build function is called as shown below at line 154.

      }
      await build(options)
    })

About me

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

Build Shadcn CLI from scratch.

References:

  1. https://github.com/egoist/tsup/blob/main/src/cli-main.ts#L1

  2. https://www.npmjs.com/package/cac

  3. https://github.com/egoist/tsup/blob/main/src/cli-main.ts#L12

0
Subscribe to my newsletter

Read articles from Ramu Narasinga directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ramu Narasinga
Ramu Narasinga

I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.