Hey guys, welcome back to Part II of my mini-image-compression app series :-) - If you haven't read Part I, you can do so right now, its only a three minutes read.

Last time, we created a simple cli-controller to just handle the userinput and print it back into the console:

The result of Part I

We can now use this functionality to forward it to imagemin/pngquant to compress our images.

The Commands/Syntax

Lets think about which commands we could need for our app to do the hard work for us - in this fashion: node run.js %arg%:

  • [filename/*] --resize [%/px] just resizes the image and overwrites the original one
    • [%/px] is an optional parameter where we can specify the output width relative (%) or absolute (px) to the original photo. Default is 1080p width
  • [filename/*] --compress [quality] determines which file type is in the input and then just compresses the images, overwriting the original one
    • [quality] just passed the according argument to imgmin/pngquant, we may need to process this argument for the libraries. Default is 70~85% quality, we'll see what's suitable

I didn't had this in mind

To process multiple arguments (especially more than two) we need to update our run.js to handle more than two arguments:

// run.js
"use strict";

// define controller to keep run.js clean
const controller = require("./src/cli-controller.js");

// grab user input with destructuring, saving it into args
const [,, ...args] = process.argv;

// function to handle user input, args is the array containing the arguments
const handleCliInput = (args) => {
  controller.helloWorld(args);
}

// run the handleCliInput function with the entered args
handleCliInput(args);

Time to destruct!1

Destructuring is so cool, now try it out to confirm that it works by running, for example: node run.js my_cat.jpg --resize 50%

Destructuring is so cool! :)

As you can see, args is an array containing all the arguments the user inputs. Cool!

The game of controllers

We want to update our controller to handle the user input properly:

// cli-controller.js
"use strict";

// define the function as a module, so we can import it in the run.js
module.exports.helloWorld = (args) => {
  console.log(`You entered: ${args}`);
}

// function that decides what do do
// remember the syntax: --(node run.js) FILENAME ARGUMENT--
module.exports.pass = (args) => {
  if(args.length > 0) { // only run this if args where provided
    console.log(`You provided the file ${args[0]}`);
    // !TODO check if file exists
    if(args.length > 1) {
      // if provided, run specific command (like --compress)
      console.log(`You requested to do >> ${args[1]} <<`);
      switch(args[1]) {
        case "--compress": // fall-through to case "compress"
        case "compress":
          if(args[2])
            console.log(`** Insert compressing here, using ${args[2]} **`); // !TODO insert compression via model here
          else
            console.log(`** Insert compressing here, using default level **`); // !TODO insert compression via model here
          break;
        case "--resize": // fall-through to case "resize"
        case "resize":
          if(args[2])
            console.log(`** Insert resizing here, using ${args[2]} **`); // !TODO insert resizing via model here
          else
            console.log(`** Insert resizing here **`); // !TODO insert resizing via model here
          break;
        default:
          console.log(`${args[1]} is not a valid parameter.`);
      }
    }
  } else {
    // warning the user that he did not provide a file. !TODO we might want to print out our apps syntax here.
    console.log(`You did not provide a file`);
  }
}

You need to catch any case that your app should do. I didn't do any verification of the user input yet, and we may want to let the libraries do it themselves, so they just throw an error. I've used switch to decide between the arguments, if you've never heard about switch, you can read about it on the MDN here. But does it work?

Yes it does work!

Wrapping it up

Today, we learned how to write a controller that decides between user input and then runs the according command. Later, we will attach those console.log's with proper functionality. I'm not so happy with the structure yet and it doesn't really meets the DRY (don't repeat yourself) standard of programming, but for now it'll work.

If you want to clone the project, you can: https://github.com/fschoenfeldt/ghost-compression

Thanks for checking out the start of my guide series for writing a (ghost) image compression app with NodeJS. If you have any questions, feel free to contact me via https://fschoenfeldt.de - Part III is coming, very soon! x

Cover-Image by NeONBRAND on Unsplash