Download a File With Progressbar Using Node Js

Today we are building a small utility to download a file with progress bar from the URL. The progress bar will indicate the progress of downloading the process. We required cli-progress package to display the progress output to the terminal.

Required Packages

Let’s start by creating a directory and name it file-download. Go the directory and install the required package.

npm i request cli-progress

Let’s create a file app.js and import all the required packages.

const request = require('request'), 
    fs = require('fs'), 
    _cliProgress = require('cli-progress');

Now we are going to create a function with the name download(). That takes the URL, filename and a callback function. We will invoke the callback once we get an error. We have some certain points where we need the callback to through an error. Like, to make sure the given URL is not dead, Or if we get an error during downloading or saving the file.

Let’s gets ready to make the download function.

const download = (url, filename, callback) => {

    const file = fs.createWriteStream(filename);
    let receivedBytes = 0
    

    // Send request to the given URL
    request.get(url)
    .on('response', (response) => {
        if (response.statusCode !== 200) {
            return callback('Response status was ' + response.statusCode);
        }
    })
    .on('data', (chunk) => {
        receivedBytes += chunk.length;
    })
    .pipe(file)
    .on('error', (err) => {
        fs.unlink(filename);
    });

    file.on('finish', () => {
        file.close(callback);
    });

    file.on('error', (err) => {
        fs.unlink(filename);
        return callback(err.message);
    });
}

If you try the above code then it will download the file from the given URL but without showing any output or progress bar. Let’s just try and check that everything working fine.

Let’s take an image URL from UnSplash website to download it to our working directory.

const fileUrl = `https://unsplash.com/photos/FHo4labMPSQ/download`;
download(fileUrl, 'knot.jpg', () => {});

Next step is to start the app by using the following command.

node app.js

Hope everything is working fine and you get the image with the name knot.jpg in your working directory. It’s bit consfused becase we should update about the downloading progress and should know how much percentage amount of completed file etc.

Add Progressbar to Download Function

Now let’s use the cli-progress package to display the progress bar, percentage and eta.

const download = (url, filename, callback) => {

    const progressBar = new _cliProgress.SingleBar({
        format: '{bar} {percentage}% | ETA: {eta}s'
    }, _cliProgress.Presets.shades_classic);

    const file = fs.createWriteStream(filename);
    let receivedBytes = 0
    

    request.get(url)
    .on('response', (response) => {
        if (response.statusCode !== 200) {
            return callback('Response status was ' + response.statusCode);
        }

        const totalBytes = response.headers['content-length'];
        progressBar.start(totalBytes, 0);
    })
    .on('data', (chunk) => {
        receivedBytes += chunk.length;
        progressBar.update(receivedBytes);
    })
    .pipe(file)
    .on('error', (err) => {
        fs.unlink(filename);
        progressBar.stop();
        return callback(err.message);
    });

    file.on('finish', () => {
        progressBar.stop();
        file.close(callback);
    });

    file.on('error', (err) => {
        fs.unlink(filename); 
        progressBar.stop();
        return callback(err.message);
    });
}