DEV Community

Cover image for 7 libraries to build Node.js CLI
🦁 Yvonnick FRIN
🦁 Yvonnick FRIN

Posted on • Originally published at yvonnickfrin.dev

7 libraries to build Node.js CLI

Last week, I wrote an article about building a Node.js CLI using yargs. I introduced it saying we use cli tools everyday to simplify common tasks in our jobs. I made myself a couple of cli like gitmoji-changelog. It is a changelog generator for gitmoji commit convention.

I would like to share with you a few libraries I used on this project and while contributing to Gatsby. Gatsby is a good source of inspiration, consider contributing to it. I learned a lot while doing it (they give free swag to thank contributions 🤫).

yargs

🔗 repository

It is a library that helps you defining your tool's interface. It also parses arguments for you. The icing on the cake is that yargs generates automatically an help menu.

Here is a simple example that displays a message "Hello [something]" a certain amount of times.

require('yargs')
  .command('$0 [name]', 'say hello', (yargs) => {
    yargs
      .positional('name', {
        describe: 'hello\'s target',
        default: 'world'
      })
      .option('times', {
        alias: 't',
        type: 'number',
        default: 1,
        description: 'number of times to say hello'
      })
  }, (argv) => {
    for (let i = 0;i < argv.times; i++) {
      console.log(`Hello ${argv.name}!`)
    }
  })
  .argv
Enter fullscreen mode Exit fullscreen mode



Result:

yargs demo

prompts

🔗 repository

A common use case in cli tools is asking user for information. Prompts is a lightweight library based on promises. It implements an exhautive list of question's types.

(async () => {
  const prompts = require('prompts')

  const response = await prompts({
    type: 'confirm',
    name: 'value',
    message: 'Can you confirm?',
    initial: true
  })

  console.log('Reponse: ', response.value)
})()
Enter fullscreen mode Exit fullscreen mode



Result:

prompts demo

signale

🔗 repository

Standard console API provides only a few methods to display information. Signale comes with 19 built-in methods (logs are prefixed with emojies ❤️)! You can also implements custom loggers.

const signale = require('signale')

signale.success('CLI started');

const options = {
  types: {
    santa: {
      badge: '👽',
      color: 'magenta',
      label: 'alien',
      logLevel: 'info'
    }
  }
}

const custom = new signale.Signale(options);

custom.santa('E.T go home')

signale.complete('Call sent')
Enter fullscreen mode Exit fullscreen mode



Result:

signale demo

chalk

🔗 repository

It is a pain in the neck to add style to a cli output. Chalk provides an easy-to-use API to colorize logs. It also supports template literals!

const chalk = require('chalk')

console.log(`${chalk.blue('Welcome')} in the activity monitor${chalk.red('!')}`)

console.log(chalk.green(`Your computer seems in ${chalk.underline('great')} shape.`))

console.log(`
envinfo:
CPU: ${chalk.red('90%')}
RAM: ${chalk.green('40%')}
DISK: ${chalk.yellow('70%')}
`)
Enter fullscreen mode Exit fullscreen mode



Result:

chalk demo

progress

🔗 repository

Another common use case is dealing with asynchronous operations. It is nice to give user a percentage of completion when your cli is doing a heavy computation. Progress is an highly customizable ascii progress bar. It comes with a bunch of options and standard information (percentage, total, estimated completion, ...) to display on the progress bar. You can also add your own information.

const ProgressBar = require('progress')

let ticks = 0

const bar = new ProgressBar(
  'Rocket launch :bar in :counter',
  { total: 10, width: 50 },
)

const timer = setInterval(function () {
  ticks++
  bar.tick({ counter: 10 - ticks })
  if (bar.complete) {
    console.log('\n🚀')
    clearInterval(timer)
  }
}, 100)
Enter fullscreen mode Exit fullscreen mode



Result:

progress demo

configstore

🔗 repository

Earlier we saw Prompts to ask user information. It is also nice to store its answer to avoid asking it again and again. Configstore is a library that persists data for you. It stores it in a json file on the user's disk. It handles well the dot notation!

const Configstore = require('configstore')
const packageJson = require('../package.json')

const config = new Configstore(packageJson.name)

config.set('answer', true);
console.log('answer:', config.get('answer'));

config.set('a.really.deep.config', true);
console.log('a.really.deep.config:', config.get('a.really.deep.config'));

config.delete('answer');
console.log('answer:', config.get('answer'));
Enter fullscreen mode Exit fullscreen mode



Result:

configstore demo

envinfo

🔗 repository

As frontend developer I use user-agent to get information about my user device. It helps a lot to reproduce bugs for example. As cli developer you don't have access to this kind of information. envinfo is a library that generates reports that users can provide when opening issues on your project.

(async () => {
  const envinfo = require('envinfo')

  const environment = await envinfo.run(
    {
      System: ['OS', 'Shell'],
      Binaries: ['Node', 'Yarn', 'npm'],
      Utilities: ['Git'],
    },
    { markdown: true }
  )

  console.log(environment)
})()
Enter fullscreen mode Exit fullscreen mode



Result:

envinfo demo

Alternatives exist for these libraries but I used these ones and I enjoy working with them. In my opinion, they covers the majority of problems you might encounter while coding cli tools.

Hope it will help 🙌 Happy cli coding!


Feedback is appreciated 🙏 Please tweet me if you have any questions @YvonnickFrin!

Latest comments (28)

Collapse
 
keivansf profile image
Keivan

Thanks a lot

Collapse
 
room_js profile image
JavaScript Room

Commander.js seems to be another good option! github.com/tj/commander.js

Collapse
 
jamesgeorge007 profile image
James George

ASCIIFIED banners can be a great addition to your CLI utilities bringing about stunning looks.

Check out node-banner

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Awesome!

Collapse
 
fedekau profile image
Federico Kauffman • Edited

Nice write up! I didn't know about some of those packages.

If you are in the process of building NodeJS CLIs you definitely should check Oclif from Heroku, I wrote a post with an example some time ago here dev.to/fedekau/building-awesome-cl...

Collapse
 
vocab_king profile image
WhistlerIAM

How about OCLIF? Have you thought of Oclif.io?

Collapse
 
angelorubin profile image
angelo rogerio rubin

The gluegun framework is also incredible.
infinitered.github.io/gluegun

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Didn't know this project, thank you for sharing 🙏

Collapse
 
terkelg profile image
Terkel Gjervig

Author of Prompts here! Thank you for featuring the prompts library ❤️

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Thank you for your awesome work 🙏

Collapse
 
therealarsam profile image
Arsam Sarabi

Commander is missing from the list 😝

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Sorry, this is an opinionated list. I use yargs for this purpose 😉

Collapse
 
pacheco profile image
Thiago Pacheco

Very nice article!
I am going to try all of this for sure, thank you for sharing.

Collapse
 
beaussart profile image
Nicolas Beaussart

I've used gluegun to create a CLI, it's quite nice and have a lot of functionality out of the box, worth checking it out!

Collapse
 
millette profile image
Robin Millette
Collapse
 
djhi profile image
Gildas Garcia

Used it with pastel for several CLIs. Really nice :)