Automation with NodeJS

5 min read

Table of Contents:

NodeJS can help you automate simple tasks. Being a web developer, you can achieve the same goals as other programming languages without having to learn them.

Introduction

Much like the previous article of Automation with Python, NodeJS can be used to automate simple tasks for you. The next task I thought would be great is converting images to webp format. Webp seems to be the future for image formats. It provides a small file size and retains a majority of the content. It helps us show the same content we love to put on the internet without having to worry about the page speed being affected too much.

Requirements

If you do not have the tools install already please visit Google's Webp to get the webp convert and visit NodeJS for the backend framework. If you want to see if you have either of them installed already, open up your terminal and type:

node -- version && cwebp -version

You should receive two separate versions on two lines. If you do not have them installed click the link above. Once those are both installed you are ready to go!

The Imports

For this project to work we need to get some classes from Node's backend libraries. These libraries allow us to interact with the file system, pathing, and executing terminal commands.

const path = require('path');
const fs = require('fs');
const { exec } = require('child_process');

Path will let us work with directory pathing, fs (short for filesystem) will let us interact with the filesystem, and the exec we are extracting from child_process will let us run terminal commands.

All of these classes are unique to NodeJS and will not work on any frontend framework. The frontend JavaScript libraries do not have access to libraries to interact with the operating system. If you try to run this code in your console of your web browser it will fail.

The Constants

I will have two constants that are used to say where the files are going to be located and what kind of photo extensions I am looking for.

const desktopPath = '/Users/user/Desktop';
const photoExtensions = ['.jpg', '.jpeg', '.tif', '.tiff', '.png'];

The tool we are using from Google to convert images over has certain restrictions. It cannot convert animated formats such as GIF. If you want to convert those you have to use another tool that Google provides in those documents.

Get the Files

Now understand with how this is setup that it will use a static path. I am having it search the desktop for all the files I want to be converted. You can change this to how you want it to work. We will now create two functions that look over the files and pick out the photos.

const isPhoto = fName => {
    let result = false;
    photoExtensions.forEach(ext => {
        if(ext === path.extname(fName)) result = true;
    });

    return result;
}
const files = fs.readdirSync(desktopPath).map(fileName => {
    return fileName;
})
.filter(isPhoto);

The bottom function will get all files and directories, the second function will get all the files that end in the format we want them to. The Map function takes a return value from a function and modifies their value. The filter value will only retain the items from the array that meet the criteria. It is the power that JavaScript has with array values.

These functions are amazing to use and are built into the core functionality of JavaScript. It is not unique to NodeJS and you should become familiar with all array functions that JavaScript has to manipulate and extract data.

Transform the Files

The last set of logic we will use is running a terminal command to convert the data. We are going to replace the \s (space)s with an escape character to ensure any file names that have spaces in them are accounted for.

Terminal commands are not a fan of spaces because they use them to separate logic. We have to add the escape so the terminal understands that they are a part of the file name and not separate commands.

files.forEach(file => {
    file = file.replace(/(s+)/g, '\$1');
    exec(
        "cwebp -q 20 " + " -o " 
        + path.join(desktopPath, file) 
        + ".webp " 
        + path.join(desktopPath, file), 
        (error, stdout, stderr) => {
        if(error) {
            console.log(`error: ${error}`);
            return;
        }
        if(stderr) {
            console.log(`stderr: ${stderr}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
    });
});

The exec will handle the execution of Google's cwebp tool to generate the files. We are using to flags here to give it some instruction.

  • -q is the quality, I have found that 20 is not a bad value to leave the compression at.
  • -o is the output filename, we are taking the original file name and just taking the .webp onto the end. I am doing it this way so we know what the original file extension is.

The callback function allows use to display the feedback from the terminal to the NodeJS console. This is a standard format of how the information is received back. Additional logic can be added here (such as additional functions) if required.

Full Code

const path = require('path');
const fs = require('fs');
const { exec } = require('child_process');

const desktopPath = '/Users/user/Desktop';
const photoExtensions = ['.jpg', '.jpeg', '.tif', '.tiff', '.png'];


const isPhoto = fName => {
    let result = false;
    photoExtensions.forEach(ext => {
        if(ext === path.extname(fName)) result = true;
    });

    return result;
}
const files = fs.readdirSync(desktopPath).map(fileName => {
    return fileName;
})
.filter(isPhoto);


files.forEach(file => {
    file = file.replace(/(s+)/g, '\$1');
    exec(
        "cwebp -q 20 " + " -o " 
        + path.join(desktopPath, file) 
        + ".webp " 
        + path.join(desktopPath, file), 
        (error, stdout, stderr) => {
        if(error) {
            console.log(`error: ${error}`);
            return;
        }
        if(stderr) {
            console.log(`stderr: ${stderr}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
    });
});

Try it Out

Put some images into the folder you added to your constant and run the Node program. You should see all of your files with their new .webp counter parts sitting next to each other.

I chose one of my files so you can see above it changed from 86kb to 12kb. That is quite a size difference! If your website has dozens of photos on it think of the change this could give you. The way I have the cwebp script setup they will retain the same dimensions. So if you need to change over a lot of images they will retain the same shape so you can 1-1 replace them.

Conclusion

This type of scripting can help take the hard work out of creating batch work. Instead of manually fixing all your documents let the computer help you and take care of the basic work. Go onto other articles I have written to help you in your future!

Recent Articles

Push Weight with Python

Create a simple terminal application that can let you know how much weight you need to put on the ba...

Validate Forms in TypeScript

Relying on HTML to validate your forms is just one step in ensuring visitors enter their information...

Automation with NodeJS

NodeJS can help you automate simple tasks. Being a web developer you can achieve the same goals as o...

Automation with Python

Python can take boring tasks away from you so you can continue to do other things. It is a scripting...

Speed With Cache in WordPress

Most WordPress sites use Apache as their server. Apache has a lot of tools built into it to speed up...

Social Media