JavaScript cli-scripts with npm

In this post, we will program a custom cli-script. You can program cli-scripts that can quickly convert gifs to mp4 files or scale down all images in a folder. All with a simple command from your terminal without installing any program or external tool.

Npm scripting basics

Npm is the JavaScript package manager. It helps you add and manage the dependencies of your program. But npm can also install simple scripts, that you can use from your command line.

Tools like create-react-app use this feature to guide you through the project setup.

Npx — the better task/script runner

To run a script like create-react-app with npm, you can either add it as a dev dependency to your project or install it globally. After that, the script is on your PATH and you can invoke it from the command line. But why do we have to install these ‘run once, installed forever’ tools before we can use them? Why can’t we invoke them right from the commandline without installing them first?

For this, npm — since version 5.2.0 — comes with a tool only crafted to help us use these scripts without installing them first. It’s called npx. So instead of doing:

npm install create-react-app -g
create-react-app my-app

We can immediatelly call this script

npx create-react-app my-app

Npx will now handle the downloading for us. (This script won’t be saved globally)

First, we have to initialize a project.

mkdir my-script
cd my-script
npm init

Now create an empty JavaScript file and name it cli.js.

Open package json and add a new property named bin.

{ 
"main": "./cli.js",
"bin": "./cli.js"
}

This property tells npm that it should add this script to the PATH on install.

Now edit the cli.js script.

#!/usr/bin/env node
console.log('Hello world!');

It is very important to add #!/usr/bin/env node to the top of our script. Otherwise our script won't be run with the node runtime.

To test if everything works, run from the project’s root folder

You should now see Hello world! printed on the command line.

Read command line arguments

Often, we need the user to pass some arguments to our script. You can easily access these arguments with process.argv. Let's print the provided argument.

Edit cli.js

#!/usr/bin/env node
const name = process.argv[2];
console.log(`Hello ${name}!`);

Call this script with the name you want.

Change the name of our command

Currently, the command we have to run, in order to execute our script, equals the name of our package. But what if we want to change the name. So instead of npx my-script, we want to call it with npx simple-script. To change the name, we need to provide an object to the bin property in our package.json file.

Edit package.json,

{ 
"bin": {
"simple-script": "./cli.js"
}
}

As you can see, the key of the provided object (here simple-script) will become the new command name. The value is the script to execute. With this method, it is also possible, to register multiple scripts per project.

{ 
"bin": {
"script1": "./cli1.js",
"script2": "./cli2.js"
}
}

Deploy your script!

You can now deploy this script to the npm or your private package registry and everyone can run your script with the command npx my-script daniel.

Make sure, that you add all your scripts to the files property in package.json. Otherwise they won't be contained in your deployed project.

Further reading


Originally published at www.danielbischoff.com on September 23, 2018.