Basic CLI in Node

Alex Korzhikov
JS Planet
Published in
7 min readFeb 4, 2019

It’s well known that Node.js is a great environment to write applications for Web.

Its journey started in 2009 when Ryan Dahl created the server-side JavaScript platform. A set of built-in libraries and Event Loop architecture felt natural to JavaScript developers and enabled them to expand their crafting areas to all kinds of projects — from simple scripts and Web servers to Internet of Things and Machine Learning.

One of the fields where Node.js is widely used is Command Line Interface (CLI) applications. In this article we overview key concepts of building a CLI program. We start with theory, explore NPM and package.json capabilities, and implement a small CLI program in JavaScript language with basic options.

Why CLI?

A CLI is a program which a user interacts within a terminal. CLI utilities are mostly used by people from Internet Technologies industry — Software Engineers, DevOps and System Administrators. CLIs` main goal is to simplify different tasks by automating and encapsulating operations into small commands.

By performing, wrapping, and combining commands in the terminal a developer can sufficiently enhance everyday working experience and speed up a development process.

With Node.js a process of making the CLI application is fast, easy, and fun because of many reasons. To start with JavaScript, which is one of the most popular programming languages in the world. It is everywhere — in browsers, server-side, devices, and cloud. JavaScript dynamic nature facilitates project extension and plug-in capabilities.

The other benefit of creating the CLI application in Node.js technology is NPM — a brilliant built-in tool allowing to organise code in packages. An enormous community allows to adapt and reuse libraries written for all possible purposes. In fact, according to Atwood’s Law

any application that can be written in JavaScript, will eventually be written in JavaScript.

Rich modules infrastructure helps developers to focus more on their application logic and makes Node.js shine in prototyping, which is highly important to prove ideas nowadays when time to market (TTM) is one of the most significant values.

Basic Principles Overview

To understand principles, concepts and best practices let’s first look at tools that JavaScript developers use in their everyday work. The one already mentioned and widely used with Node.js infrastructure is NPM. When typing npm in a command line it immediately shows a help message

NPM shows which commands are possible to be executed as well as basic information about the program. Note, that the message is shown without being said to do so. This is default behavior, when there is no input given. It makes the help command accessible. To make it also predictable, it makes sense to enable a help option without strong syntax.

All four commands examples above output the same NPM help message. Additionally, it is useful to show the help message if the given input is not recognised.

The other tool developers are probably using most of their time is Git - an open-source version control system program for the terminal. It also shows a help message as default action when called without arguments.

However, it’s just a few examples, undoubtedly, this can be treated as the starting point command in all CLIs applications. Its purpose is to allow the developer to understand what he can do with the utility. A program that doesn’t have a “help” command is hard to use. The user might have got stuck and just leave it as it doesn’t allow him to achieve his goal.

Let’s write a requirement for the further implementation in a Gherkin notation, we’ll use it later.

The next thing the one might notice in NPM help message above is the program’s version shown at the bottom of it.

npm@6.4.1

It’s another common CLIs practice, which helps the user to understand how to use the tool and not to be stacked with unexpected behavior. Usually, by searching an answer of how to solve a task the user finds some documentation on the Internet (say, at Stack Overflow). It can be unclear, why the answer does not work. Explicitly showing the version helps to stay in touch with actual software. The program’s — version option would respect user’s expectations in that scenario.

Some CLIs show a warning if there is a newer version available, or even propose an automatic update while using a tool. Let’s write the version requirement for later.

First CLI

We are going to work with the Linux shell to write the very first CLI program. The basics examples will also work in Mac OS. We’ll need Node.js to be installed on a machine. Its version doesn’t matter much at that point, but we’ll use the Long Term Support (LTS), which is currently 10.

The NPM doesn’t need to be installed separately, as it goes together with the Node.js package. Let’s do the first step — introduce a package, that we’ll work on.

With these commands we’ve created the simplest application in Node.js. In all of them we’ve used different command line tools, such as mkdir, cd, echo, and, finally npm. When running the last step, the output should be like

Our first goal is to create something very simple, and in next tutorials we’ll make the CLI as powerful as the commands above.

By the way, just to be consistent with our intent, we’ll add the generated code to a version control system, and we’ll use Git to save the state.

The created code is still far from being a CLI. We ran it with npm command during the initialisation and could also use node for the same reason.

Here is where NPM really shines. Let’s add a bin property to package.json file

The bin property, when a package is installed signals to NPM, that the command with the package name should be added to PATH. After installing the package globally

It is possible to run the my-cli command in the terminal at any location. NPM made the server.js file executable. A normal install puts the bin file onto node_modules/.bin directory of a project and enables to run it with an npx command. By running an npm link command we create a symbolic link with the package and make it easier to develop and debug.

However, the output is not a desired “Hello, World!” string. That is because in *nix systems when an executable is started, it’s interpreted with shell sh. To let it know, that it needs to be executed with node we need to add a shebang at the beginning of the server.js file.

Now, my-cli outputs “Hello, World!” like it was expected, and it’s time for us to implement version and help behaviours.

We don’t want to repeat ourselves with duplicating information in many places. So, we’ll use package.json fields — name, version, and description as the single source of truth for that program.

Next, we’ll retrieve the data from package.json and show it as the default message when running the CLI.

The last part parses given arguments as options and decides which value to show. We’ll use the global variable process available in Node.js environment and it’s property process.argv. argv is an array, with first item — a path to Node.js runner version and the second — the program path. The rest is all passed arguments split by whitespace. That can be shown with an added expression console.log(process.argv). When running in

my-cli test=me option

the output will be

Remember, we've decided output the program's version when an appropriate version is passed

Here is the code, implementing this requirement

On the fourth line, we slice the passed arguments array, excluding it’s first two items. The latter logic is quite obvious — if options contain — version flag, we output the version from package.json. Otherwise, we still output the help message. Good news is that our first required scenario

also nicely passes now. Our work is done for now!

In this article we’ve reviewed basic aspects of building a CLI in Node.js. We looked into NPM and git default commands output, and implemented the small JavaScript program showing help and version messages. In the next part, we’ll overview a landscape of existing tools and libraries and continue building a Command Line Interface application.

This is a part of “Crafting Notes CLI in TypeScript” workshop and tutorials performed by JavaScript Planet — a group of software engineers, instructors, and Web enthusiasts. Our goal is to help developers to extend their knowledge and improve software programming skills.

--

--

Alex Korzhikov
JS Planet

Software engineer, instructor, mentor, and author of technical materials #JavaScript