We're planting a tree for every job application! Click here to learn more

How to make beautiful, simple CLI apps with Node

Hugo Di Francesco

21 Jun 2018

2 min read

How to make beautiful, simple CLI apps with Node
  • Command Line

Channel your inner Sindre Sohrus and ship a beautifully simple CLI app using Node.

Command line apps are a neat way to package repetitive tasks. This will walk you through some tools that are useful to build CLI apps.

  • The idea 💡
  • Piping to the command line 🚇
  • Dealing with sequential actions ✨
  • Executable JavaScript files 🦅
  • Adding package binaries 📦
  • Publishing to npm 🚀

The idea 💡

When merging/rebasing, the file that always seems to cause trouble is the package-lock. We’ll go through how to make a simple utility that deletes the package-lock.json file, regenerates it (npm install) and adds it to the git index.

You can find it here: and run it using npx fix-package-lock.

Piping to the command line 🚇

To start off, we’ll leverage a package from Sindre Sohrus, execa, which is described as “a better child_process”. For the following snippet to work, run npm install --save execa:

index.js

const execa = require('execa');
execa('ls').then(result => console.log(result.stdout));
node index.js
index.js
node_modules
package-lock.json
package.json

Dealing with sequential actions ✨

To re-generate the package-lock we’ll need to first delete it, then run an npm install.

To this end, we can use Listr, it allows us to do things that look like:

Hugo article gif.gif

Run npm install --save listr and add leverage Listr as follows:

index.js:

const execa = require('execa');
const Listr = require('listr');
new Listr([
  {
    title: 'Removing package-lock',
    task: () => execa('rm', ['package-lock.json'])
  },
  {
    title: 'Running npm install',
    task: () => execa('npm', ['install'])
  },
  {
    title: 'Adding package-lock to git',
    task: (ctx, task) =>
        execa('git', ['add', 'package-lock.json'])
        .catch(() => task.skip())
  }
]).run();

Now the output of node index.js looks like the following:

Hugo article image # 2.jpeg

Listr gives you a loading state when you have a long-running task that returns a Promise (like the execa invocation of npm install).

It’s also possible to display a message that changes using Observables, for more information see the Listr docs

Executable JavaScript files 🦅

It’s ideal to be able to execute our script using ./index.js instead of node index.js.

To do this, we need the file to be executable on UNIX systems that’s: chmod +x. So

chmod +x index.js

We then need to inform the system how it should attempt to run the file, that’s using the following hashbang:

#!/usr/bin/env node

If we add it to index.js we get:

#!/usr/bin/env node
const execa = require('execa');
const Listr = require('listr');
new Listr([
  {
    title: 'Removing package-lock',
    task: () => execa('rm', ['package-lock.json'])
  },
  {
    title: 'Running npm install',
    task: () => execa('npm', ['install'])
  },
  {
    title: 'Adding package-lock to git',
    task: (ctx, task) =>
        execa('git', ['add', 'package-lock.json'])
        .catch(() => task.skip())
  }
]).run();

Which we can now run using:

./index.js

Adding package binaries

npm has a bin field which we can use like the following (in package.json):

{
  "name": "beautiful-cli",
  "version": "1.0.0",
  "description": "A simple CLI",
  "main": "index.js",
  "bin": {
    "fix-package-json": "./index.js"
  }
  "dependencies": {
    "execa": "^0.10.0",
    "listr": "^0.14.1"
  }
}

Publishing to npm 🚀

This is left to the reader as an exercise, although using the np package, it’s super straightforward.

Hint: run npx np in whatever package you’re trying to publish.

You can find the full package here and run it using npx fix-package-lock.

Did you like this article?

See other articles by

Related jobs

Title

The company

title

Remote

Title

The company

title

Remote

Title

The company

title

Remote

Title

The company

title

Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
email iconhello@works-hub.comUK flag

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

US flag

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2021 WorksHub

Privacy PolicyDeveloped by WorksHub