DEV Community

Kenneth Mark
Kenneth Mark

Posted on

How to write a simple CLI in Node.js

I recently took it upon myself to write a simple CLI for code generation for an enterprise application for my current employer. The goal of the CLI was to make it easy to create files and components as we were using the atomic design system. Not to explain in depth, but atomic design consists of breaking down your components into atoms, molecules, organisms,templates and pages, all of which were nested in the components folder located in the src folder at the root of the project.

So to make it easy for the developers on our team to follow this design system, it was suggested a CLI be implemented to make this process enjoyable for all developers and encourage adoption.
The goal of the CLI, was to prompt questions and then use the answers to generate the a file, a storybook story and then copy default templates into these files so the component is already set up with the basics such as the default imports, defaults exports and component name.

In pseudocode:

- Ask what type unit do you want to create. Could be one of atom, molecule, organism etc
- Ask for name of the file and format it
- Get answers above and create a folder and file based on these answers 
- Use created templates and replace 
Enter fullscreen mode Exit fullscreen mode

Using Inquirer

In the Node.js ecosystem, there are a lot of CLI libraries such as inquirer, commander, yargs, args etc. They all serve different purposes and sometimes share funtionality but inquirer seemed the most appropriate for this project. It's API looks very human readable and subjectively easy to implement.

const inquirer = require('inquirer');

inquirer
  .prompt([
    /* Pass your questions in here */
  ])
  .then(answers => {
    // Use user feedback for... whatever!!
  })

Enter fullscreen mode Exit fullscreen mode

The key to understand and using inquirer is passing in questions to the prompt method. A question is an object that should look like this:

{
  message: "What is your name?",
  type: input | number | confirm | list | rawlist |  expand | checkbox | password | editor,
  choices: ["Kenny","James"],
}

Enter fullscreen mode Exit fullscreen mode

Here is an actual example of a complete implementation adapted from here

const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'rawlist',
      name: 'theme',
      message: 'What do you want to do?',
      choices: [
        'Order a pizza',
        'Make a reservation',
        'Ask opening hours',
        'Talk to the receptionist',
      ],
    },
    {
      type: 'rawlist',
      name: 'size',
      message: 'What size do you need',
      choices: ['Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'],
      filter: function (val) {
        return val.toLowerCase();
      },
    },
  ])
  .then((answers) => {
    console.log(JSON.stringify(answers, null, '  '));
  });
Enter fullscreen mode Exit fullscreen mode

THe example above is a bit self explanatory, it should initially prompt the user what if wants to and upon selecting their choice, it would move on the next question which is asking for the size of the chosen pizza. The answers would return an object that should look like this:

{
  theme:"Make a reservation",
  size:  "jumbo"
}

Enter fullscreen mode Exit fullscreen mode

The answers object would look slightly different is the type of prompt is something like a checkbox, in that question the value would be an array instead of a string.

To run this, ensure you first have the library installed and then put it in a file are the root and then run node [file].js
If inquirer doesn't suffice, you can look into combining it with a couple of the libraries I have mentioned above such as commander or yargs. These libraries allows you to accept arguments, produce default help menu, versioning etc.

Top comments (0)