Nodejitsu

Save time managing and deploying your node.js app

Nodejitsu has joined GoDaddy

We are excited to join GoDaddy to help spearhead their largest Node.js product: Website Builder. Please read our blog post to learn more about customer transition plans and our continued support for Open Source within the node community.

Want to know all the details?
Read the full blog post or read the GoDaddy Announcement.

npmawesome: Progress reporting in CLI applications

About the author

Name
Location
Worldwide
nodejitsu nodejitsu

Other popular posts

- Scaling Isomorphic Javascript Code - Keep a node.js server up with Forever - Package.json dependencies done right
- npm cheat sheet - 6 Must Have Node.js Modules

This is a guest post from Alex Gorbatchev and npmawesome.com. Nodejitsu loved what Alex was doing at npmawesome.com and is now supporting the project. Like what you see here? Why don't you contribute on Github?

Lets talk about long running CLI (command line interface) applications. When you have a finite process that is expected to take some time, the best thing to do is to let your users know about it. A typical application that for example downloads a file might look like this

var
  request = require('request'),
  fs = require('fs')
  ;

process.stdout.write('Downloading... ');

request('http://nodejs.org/dist/node-0.0.1.tar.gz')
  .pipe(fs.createWriteStream(__dirname + '/node.tar.gz'))
  .on('close', function (err) {
    process.stdout.write('done!\n');
  });

The user experience is hardly a great one. It's clear that something is happening, or at least expected to be happening.

It's not really clear if it's still happening. Is it time for ctrl+c yet? How about an indicator that something is actually going on?

process.stdout.write('Downloading...');
intervalId = setInterval(function() { process.stdout.write('.'); }, 1000);

request('http://nodejs.org/dist/node-0.0.1.tar.gz')
  .pipe(fs.createWriteStream(__dirname + '/node.tar.gz'))
  .on('close', function (err) {
    process.stdout.write(' done!\n');
    clearInterval(intervalId);
  });

A little better. But still, there's no way of telling how long the process will actually take. Lets just do a real progress bar, shall we? This is where progress (Github: visionmedia/node-progress, License: MIT) module that was originally started by TJ Holowaychuk comes into play! Due to the awesomeness of open source, progress is now pretty much a community effort.

npm install progress

Features

progress supports a wide range of options via the format string and options. In the end will get a good looking ASCII progress bar and that will let everyone know about the true progress in your CLI application.

These are the tokens you can use to format your progress bar:

  • :bar the progress bar itself
  • :current current tick number
  • :total total ticks
  • :elapsed time elapsed in seconds
  • :percent completion percentage
  • :eta estimated completion time in seconds

Usage

Lets modify our original example and put progress to a good use:

var
  request = require('request'),
  ProgressBar = require('progress'),
  fs = require('fs')
  ;

var
  req = request('http://nodejs.org/dist/node-0.0.1.tar.gz'),
  bar
  ;

req
  .on('data', function (chunk) {
    bar = bar || new ProgressBar('Downloading... [:bar] :percent :etas', {
      complete: '=',
      incomplete: ' ',
      width: 25,
      total: parseInt(req.response.headers['content-length'])
    });

    bar.tick(chunk.length);
  })
  .pipe(fs.createWriteStream(__dirname + '/node.tar.gz'))
  .on('close', function (err) {
    bar.tick(bar.total - bar.curr);
  })
  ;

We even get ETA estimate for free. That's what I'm talking about!

Other modules to checkout

Here are a few other modules to check out:

Closing thoughts

It's really cool to see a CLI application giving meaningful progress feedback. Please don't forget about user experience when building tools.