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!

Top comments (28)

Collapse
 
saurabhdaware profile image
Saurabh Daware 🌻 • Edited

I absolutely love prompts! I recently switched from inquirer to prompts and it helped me reduce my dependency tree.

I love commander as well, It has 0 sub dependencies and since it is popular it has good resources available (there are a lot of articles available about commander).

Great article🦄 I haven't heard about a lot of them before.. I'll give them a try :D!

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Thank you 🙏Yesterday, I asked someone why using inquirer over prompts. Thank you for the dependency tree argument 👍

Collapse
 
terkelg profile image
Terkel Gjervig

Thank you Saurabh, I'm glad you find Prompts useful!
Few dependencies are one of the main goals of Prompts - High five! 🖐

Collapse
 
gomflo profile image
Hugo Gomez

inquirer and ora are also good

npmjs.com/package/inquirer

inquirer

npmjs.com/package/ora

ora

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

I used them too but I did a choice for the article 😢

Thank you for talking about them 👌

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Might want to include some logging libraries next?

Segway: one thing I learned from other languages is your cli is just a client and you should keep the functionality in a separate libe that exposes bindings to this client or any future applications.

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

I'm not familiar with the subject but it seems interesting (I might need this on an issue on gitmoji-changelog, since I want to use it on a website). Do you have some articles about it? Maybe a library you had in mind?

Collapse
 
vocab_king profile image
WhistlerIAM

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

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

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

Collapse
 
angelorubin profile image
angelo rogerio rubin

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

Collapse
 
tomekbuszewski profile image
Tomasz Buszewski

I am such a fan of Signale and Prompts. I love how simple, yet effective they are.

Collapse
 
terkelg profile image
Terkel Gjervig

Prompts is also a fan of you 🎉

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

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

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
 
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
 
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
 
steeve profile image
Steeve • Edited

Thanks for this article! I have to try everything 🐘

Collapse
 
yvonnickfrin profile image
🦁 Yvonnick FRIN

Thank you 🐘