Node.JS | Build a Command Line (CLI) Tool in NodeJS

Command line applications (CLI) are often the core tools for automating tasks, such as deploying production applications, running tests, building reports, migrating data, DevOps, and the list goes on and on. If you find yourself doing the same things over and over again, chances are you can automate those steps with a script and save yourself a lot of time!

Node.js is a great solution for writing CLI apps. Node.js itself has built-in libraries for reading and writing files, launching other applications, and basic network communication. Since the advent of Nodejs, command-line tools have been built using the JavaScript programming language, the most popular and widely used language in the world. There are many popular CLI tools built using JS:

  • NPM
  • @angular/cli
  • create-react-app

These are popular CLI tools we have in npmjs.org. NPM is the world most popular Node package manager. You reading this, you must have worked with Nodejs, and there is no way you haven’t used the popular npm command with its helluva pile of sub-commands:

  • publish
  • init
  • cache clean
  • etc

Introduction

You see, Nodejs made us be able to write command-line tools in our fav language: JS. Without Nodejs, we will just write a cmd0line in C/C++ and compile to executable. We know the popular commands we use in cmd/bash:

  • ls
  • touch
  • mkdir
  • cd
  • etc

These are executable files(.exe, .app, in Linux systems there is no file extension) in our system path, written in C/C++ and compiled to executable format. If we run the ls command to list files and folders in our current directory:

$ ls
'autorun.inf/' 'System Information/'

The ls file is forked and run, the results it returns is displayed on the cmd/bash/sh.

we can create our our program and run it in cmd-line:

// hello.cpp
#include <iostream>;
int main() {
 cout >> "Hello world";
 return 0;
}

On compilation, we will have the executable file hello.exe. On execution in he cmd-line, it will display “Hello world” in the cmd:

$ hello
Hello world

You see, this is a CLI tool written in C/C++ but with Nodejs we can write the same in JavaScript, can you imagine that? A language we knew from the beginning of our programming journey that it was a browser-based language, can now be used to create CLI utilities that can be done in C/C++.

So, in this post, we will see how to write a CLI tool in JS.

Project construction

First, you need to download the Nodejs program and install it. Open your browser and navigate to https://nodejs.org and there on the main page you can download the version of Node.js that corresponds to your platform.
Next, we have to initialize a Node project:

mkdir node-cli
cd node-cli
npm init -y

This app will mimic our hello.cpp program it will just output "Hello world" in the terminal.

We create an index.js file

touch index.js


Open it and pour in the below contents:

// index.js
console.log("Hello world");

If we run node . in our terminal, we will see the contents display:

$ node .
Hello world

We added . to the node command because the entry point is the index.js so Node will know to run the index.js file which is the default file for any Node project. If we create a file like hello.js, to run it we must specify its name in the node command: node hello or node hello.js.

I know, a Hello world program isn’t ideal to demonstrate a concept but this isn’t about the example it is about how to make a shell-command line program in Nodejs.

Making our project a Shell-Cmd

Our program is called with the node command, we want it to be called like a regular shell command like how the Angular CLI is called: ng.
It is very easy to achieve. First we add #!/usr/bin/env node to the index.js file:

// index.js
#!/usr/bin/env node
console.log("Hello world");

This makes it possible to execute this project without the node command. See it has already been added in the command #!/usr/bin/env node.
Next, we need to update our package.json file:

// package.json
{
 name: "node-cli",
 // ...
 bin: "./index.js"
 // ...
}

See we added a bin property with the value pointed to the index.js file. The bin prop specifies command names for a node project, but as we have a single file the name property will be used as the shell command name.

Now our app is not globally available like we cannot run node-cli in our shell to run the project. But we don’t want the CLI name to be node-cli, we want it to be hello, so we can run it like this: hello. To do that we will change the name property in the package.json to hello.

// package.json
{
 name: "hello",
 // ...
 bin: "./index.js"
 // ...
}

Making our project globally available

To make our project available globally we would create a symlink using the npm link command.
We run:

npm link
yarn link

in our project. This command creates a symbolic link between the project directory and executable command.

In Windows, you will see hello.cmd created in ~/Admin/AppData/LocalRoaming/npm, the hello.cmd is the file that will be run when we type hello in cmd/bash/sh in any directory.

To test it, make sure you are not in the project directory. Open cmd/bash/sh and type hello:

$ hello
Hello world

Boom!!! our Node app works globally in our machine!

Publishing our project to NPM

To be able for users to install our node project and use it globally in the machine, we have to push it to NPM.

Before pushing our project, we need to bet or ignore some files or folders, node_modules is the main folder that is usually ignored because when the dependencies in the node_moduleswill be installed when the users pull in our project.

Since we have not installed any dependencies so we have no node_modules folder, but if to say we have it. To ignore it is easy just create .npmignore file and add the node_modules folder in it.

// .npmignore
node_modules/

We can then push our project to NPM:

npm publish
yarn publish
+ hello@0.0.1

Users can install our hello project globally:

npm i hello -g

The user can run the hello command in the shell like this:

$ hello
Hello world

Adding commands to our project

A node project can have many commands. Our hello project has one shell command hello, we can add many commands to it.

We can add commands like:

  • sayName: says my name "Chih- Yu Lin" and my details like age, career.

  • tip: gives a tip of the day.

  • today: prints today’s date.

To do that we will edit our package.json

// package.json
{
 name: "hello",
 // ...
 bin: "./index.js"
 // ...
}
|
 |
 v
// package.json
{
 name: "hello",
 // ...
 bin: {
 "hello": "./index.js",
 "sayName": "./sayName.js",
 "tip": "./tip.js",
 "today": "./today.js"
 }
 // ...
}

The bin property is now an object that holds the command and its corresponding file to call.
Now, let’s create the files:

touch sayName.js
touch tip.js
touch today.js

Then, we flesh them out.


#!/usr/bin/env node
// sayName.js

console.log("Im Chih- Yu Lin\n")
console.log("I am a Software Developer")

#!/usr/bin/env node
// tip.js

console.log("Never give up")
console.log("There is light at the end of the tunnel")

#!/usr/bin/env node
// today.js

console.log("Today's date is " + Date.now().toLocaleString())

Now our node-cli project folder would look like this:


node-cli
 index.js
 sayName.js
 tip.js
 today.js
 package.json
 .npmignore 

Run the npm link to create symlinks for our new commands. You can also publish the new updates to NPM to add the new commands.
After done with that, our users can use our commands as shell commands:

Learn More

Thanks for reading !

#nodejs #node #javascript

Node.JS | Build a Command Line (CLI) Tool in NodeJS
2 Likes33.15 GEEK