Writing an image compression app (for Ghost) with NodeJS, imagemin & pngquant (Part II)
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:
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);
const [,, ...args] = process.argv
simply passed all input after run.js into theargs
array. Read more about destructuring on MDN if you're not sure what it does.const handleCliInput = (args) => { /* ... */ }
I didn't explain this in the last article, but this is a special way to assign a function - called arrow function. You could also do the classicconst handleCliInput = function(args) { /* ... */ }
expression. Read more about arrow functions on MDN.
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%
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?
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