Simple interactive CLI tool in Node/Javascript

rohit_ambre

Rohit Ambre

Posted on March 25, 2024

Simple interactive CLI tool in Node/Javascript

I was always fascinated with CLI tools provided by different applications, thinking that how simple and easy commands on CLI can result into such a big actions which can take quite a time to navigate through the UI.

At my workplace I had one task that has to be done manually every time there's a need of doing it, which is a step-by-step process so I was thinking of automating it my level. I had two options, one is creating a small UI and other one is creating CLI tool. Me already wanting to create a CLI tool obviously chose a CLI tool 🤩.


Here I will give you a small example about how can you create simple but very effective CLI tool in nodeJS Using Commander and inquirer packages.

Requirement

If you're going to use inquirer

NodeJS version >= v18.12.0

We're going to create a small Burger maker tool, which will accept inputs about bread, patty, toppings etc

  • Commander is used to create CLI tool with commands and flags.
  • inquirer provides ability to ask questions, interactivity and actions on the basis of answers.

Implementation

Start a new javascript project with npm init -y
inquirer v9 uses esm modules hence you cannot use commonjs syntax, to change your project to use module import/export change type property in your package.json file to module. You can read more about esm modules here.

Import commander and inquirer



import { Command } from 'commander';
import inquirer from 'inquirer';


Enter fullscreen mode Exit fullscreen mode

create a new Program using Command class and add name along with some description.



const program = new Command();
program
    .name('burger-maker')
    .description('Order a burger from CLI')
    .version('1.0.0');

program.parse();


Enter fullscreen mode Exit fullscreen mode

Now, try running your basic command on terminal.
It should display command description with available options.

burger-maker help

Now, add order command to the program and create basic questions using inquirer prompts



const prompts = [
    {
        name: 'name',
        message: 'Your Name?',
        validate: function(name) {
            if (!name) {
                return "Name is required"
            }
            return true
        }
    },
    {
        name: 'bun',
        message: 'Choose a bun?',
        type: 'rawlist',
        choices: ['Classic', 'Whole Wheat', 'Gluten Free'],
        default: 'Classic'
    },
    {
        name: 'patty',
        message: 'Choose a patty?',
        type: 'rawlist',
        choices: ['Veg', 'Chicken', 'Today\'s Special'],
        default: 'Veg'
    },
    {
        name: 'toppings',
        message: 'Choose your favourite toppings',
        type: 'checkbox',
        choices: ['Tomato', 'Lettuce', 'Cheese', 'Onion']
    },
    {
        name: 'sauces',
        message: 'Choose your favourite sauces',
        type: 'checkbox',
        choices: ['Mayonnaise', 'Ketchup', 'Mustard']
    },
]


Enter fullscreen mode Exit fullscreen mode

These prompts are self explanatory, there are different types of prompts offered by inquirer like input, list, rawlist, checkbox, password etc. Prompts with documentations can be found here github

Add action listener on created order command like below



.command('order')
.description('Order a burger')
.action(async function(){
    const answers = await inquirer.prompt(prompts)
    console.log(answers) 
})


Enter fullscreen mode Exit fullscreen mode

Now, when you run your order command you'll get prompts to input the order details.

order command output

At this point you can do whatever with the response, you can make http api call and save in database.
You can also make nested prompts to gather more information about particular item like below



const answers = await inquirer.prompt(prompts)
console.log(answers)
if (answers.patty === 'Chicken') {
     const pattyAnswers = await inquirer.prompt([]) // new prompts here
}


Enter fullscreen mode Exit fullscreen mode

I also added small spinner by nanospinner and printed placed order details after a small delay.


Make it Globally available

  • Update main property in package.json to index.js
  • Add #! /usr/bin/env node at the top of your file (this lines tells your OS to run this file with node interpreter)
  • Add bin property to package.json as follows. ```json

"bin": {
"burger-maker": "./index.js"
}

- Run `npm install -g .` to install this app 
- Now, open a new terminal and run `burger-maker -V`

![Final command output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9iq8gtx3ush09jemxach.png)

NOTE: 

- if you're using Typescript give a path to a `dist/index.js` file
- If you're using `nvm` make sure correct node version to run the command

### ✅ There you go, You have your first CLI tool.
---
My example code is available on [Github Repo](https://github.com/rohit-ambre/burger-maker-cli/).



Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
rohit_ambre
Rohit Ambre

Posted on March 25, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related