Building a CLI tool using node - An Ultimate Beginners guide 🚀
Tags: javascript, node, npm, webdev
Published: 2021-12-06 18:00:20

## What is a CLI Tool
A tool that allows you to perform certain tasks or operations right from your terminal is a CLI tool.

As a programmer 👨‍💻, we use CLI tools on daily basis, from creating projects to managing versions of the projects, CLI is everywhere. In this article, we will explore how you can create a CLI tool on your own from scratch and publish it on npm. We will use Nodejs for this purpose, but first, let’s understand what are the perks of using nodejs:

- Nodejs has a handful of packages and libraries to do a variety of tasks.
- [npmjs](https://www.npmjs.com/) is the world's largest software registry with thousand of packages, where we can publish ours.
- By creating a CLI in node:
 - We can automate repetitive tasks.
 - We can create and publish open-source npm packages like create-react-app.
 - We can create troubleshooting tools, etc

## Prerequisites
To build a CLI in Node, you should have the prior knowledge of:
- Fundamental JavaScript (not vanilla)
- Basics of nodejs & npm
- Asynchronous JavaScript

In this article, we will create a CLI tool that generates random passwords from your terminal.

## Setting up the project

First, we will create a directory that will keep our cli code:
```bash
mkdir random-password-generator
cd random-password-generator
 ```
After creating the project folder we have to initialize our nodejs project

```js
npm init
```
It will ask some questions from you, you can also use `npm init -y` to set the default values. This will create a package.json file.

### What is package.json file
The `package.json` file is the heart of any Node project. It records important metadata about a project which is required before publishing to npm, and also defines attributes of a project that npm uses to install dependencies, run scripts, and identify the execution point to our package.

## Creating the CLI tool:
Create a file `index.js` in the root of the project directory. This will be the main starting point of the execution and it'll run all the associated functions and commands.
Now let's begin to create our cli tool. Our cli tool consists of the following features:

- Randomly generates strong passwords.
- Automatically copy passwords to the clipboard, when created.
- Have a history feature that shows the lastly created password.

To implement the random password generation functionality paste the following code.

```js
const chars = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let passwordLength = 30;
let password = "";

for (let i = 0; i <= passwordLength; i++) {
    let randomNumber = Math.floor(Math.random() * chars.length);
    password += chars.substring(randomNumber, randomNumber + 1);
}
```
This will generate a random password on every run.

![Console Output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vflapi5fhm4q3ccz1ye.png)

Perfect, a strong random password is generating on every run but if you notice to generate the password you have to run `node index.js` every time which is not ideal, especially in the case of a cli tool. We are supposed to write a command for example __passgen__ or __pswdgen__ to generate the passwords. So, to achieve this functionality we have to modify our `index.js` and `package.json` files. In the index.js file add this line
```bash
#!/usr/bin/env node
```

The above line is called shebang. It tells the system to execute the code using the node environment. Make sure to add it to the first line of your main execution file. In `package.json` add the following code above the __main__ key in such format "main-command-name": "main-file-path", In our case:

```json
"bin": {
    "pswdgen": "./index.js"
  },
```
Now, to generate the password you simply type pswdgen on the terminal but to enable it and test your cli locally you have to link it first. To link the cli run the following command.
```js
npm link
```
> if you face any error try to run it with a -f flag

The output would be

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/174svpe7thfx0soew4m0.png)

Now we work on the auto copy feature of the cli. For this purpose, we use a package named [clipboardy](https://www.npmjs.com/package/clipboardy). To install run
```js
npm i clipboardy@2.3.0
```
To automatically copy the password on the clipboard we simply have to add this line after the loop
```js
 clipboard.writeSync(password)
```
> Make sure you import clipboardy

Now, we implement a history feature through which we can view the lastly created password through the `-h` or `--history` flag. For this purpose, we use [conf](https://www.npmjs.com/package/conf) package. But first, let's create the flag feature. We use `process.argv`for this purpose, `process.argv` is an inbuilt API used to get the arguments passed via command line like `-h`. We will slice it to remove the first two indexes of it to get relevant data only.

```js
const flags = process.argv.slice(2);
```

Now to store password we use the following code
```js
config.set('prevPassword', password);
```
> Make sure to import and initialized conf as follow

```js
const Conf = require('conf');
config = new Conf();
```
To use `-h` feature only when requested we make it sure to use the get history code of the conf in a `if` statement as follow:

```js
 if (flags[0] === '-h' || flags[0] === '--history') {
        console.log(config.get('prevPassword'));
    }
```
> Also make sure to use the mentioned code above the config.set code.

The output would be
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r14aae6v9pzhvzm88uds.png)

Our cli is complete 🎉🎉 but if you notice at the codebase all things are coded on a single function and file which makes codebase messy and also it will become hard to debug as it increases and the interface of the cli is also not good and user friendly, the user didn't get any idea of the password, as it copies on the clipboard or not.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjt78dvv7kctejwr9hdd.png)

First, instead of a single function let’s divide it into multiple functions according to their functionality. It will be divided into four functions `passwordGenerator`, `copyToClipboard`, `savePassword` and `history`. Now we will create a separate folder named `functions` and create a file for each function respectively. Now, we work on the interface of the cli. For this purpose, we use 2 packages.
- [cli-welcome](https://www.npmjs.com/package/cli-welcome) for a welcome cli header
- [chalk](https://www.npmjs.com/package/chalk) to style the output string.

To install cli-welcome, run
```
npm i cli-welcome
```
We will create a folder name `utils` and create a file `header` in it where we add the following code
```js
const welcome = require('cli-welcome');

module.exports = () => {
    welcome({
        title: `password-generator-cli`,
        tagLine: `by Meer Hamza`,
        bgColor: `#00ff00`,
        color: `#ffffff`,
        description: `randomly generates strong passwords`,
        bold: true,
        clear: true,
        version: `1.0`
    });
}
```
and now simply import this file and call the header function above all the function calls. This will generate this beautiful header

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2k34rv73gng5zct99awo.png)

Now, in the `utils` we create a file, name `cli` or `body` and paste the following code and its associated imports from the `index.js` to it.

```js
    const config = new Conf();
    const flags = process.argv.slice(2);

    if (flags[0] === '-h' || flags[0] === '--history') {
        history(config)
    }
    else {
        const password = passwordGenerator();
        copyToClipBoard(password);
        savePassword(password, config);
    }
```
Now, we beautify the output and the copy to the clipboard message using the chalk. To install chalk, run
```js
npm i chalk@4.1.2
```
Now, we will style different things like `password`, `previous password` etc. for example to style copy to clipboard message we write the following code

```js
console.log(chalk.gray('Password copy to the clipboard'))
```
The final look of the cli will be:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc4yt0mkofio0rvl58w4.png)

with  `-h` flag

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t237y73zmf3iwu9qhq48.png)

## Publishing the CLI tool
After creating the cli, to make it accessible to everyone we publish it to [npm js](https://www.npmjs.com/), which is the home of thousands of packages, as a package. So, make sure you have created an account on the npmjs. After the account creation, run the following command in your terminal

```js
npm login
```
You will be asked to enter your username, password, and email. If all is correct, you will be logged in.

Then, to publish your cli run

```js
npm publish
```
This command publicly published your cli on npm with the name specified in project's `package.json`.

```json
"name": "package-name",
```

It can also give the error if another package with the same name exists. Keep in mind there's a difference in `name` and `command-name` we specified in the _bin_ attribute, `name` is used to download packages from npmjs while `command-name` specified in the _bin_ used to run cli and functions. To install your package from _npm_ simply run 

```js
npm i -g pswd-generator-cli
```
> Whenever you make changes in the CLI, you have to change the version in the `package.json` and then republished the changes otherwise it will give error.  

## Conclusion

Congratulations, you learned how to create a CLI tool using Node.js 🎉🎉. The sky is the limit, go create something awesome. I also created an open-source template so you don't need to start everything from scratch. 
[github.com/meerhamzadev/node-cli-template](https://github.com/MeerHamza1421/node-cli-template)

> code link: [code](https://drive.google.com/drive/folders/1ZiSjiD5EL-BjMtdS3Ovbib7FUIOW6O8-?usp=sharing)