Writing an image compression app with NodeJS, imagemin & pngquant (Part III)
Part III into writing an image compression app with NodeJS, imagemin & pngquant.
Hey guys, welcome back to Part III of my mini-app-cli-ish image compression series! If you haven't read part Part II, you can do so here. By the way, ghost added image compression to their core so your images will be compressed automatically by default!
Anyway, I'll continue this tutorial series because I'm starting a new Fotohaecker Project from scratch with Elixir & Phoenix Framework and I need a compression CLI to process users photo uploads.
Updating our dependencies
Because my last post is a bit old, we first want to check for dependency updates. For this, I find two libraries very useful: npm-check-updates and npm-check. The first one is more popular but the second has a graphical User-Interface - so you decide!
npm-check (note, I added the
-u flag to skip unused dependencies warnings, as we haven't actually used mozjpeg etc., yet.)
Now, lets get started with the actual compression of our images. It's triggered by the CLI command
node run.js foo.jpg --compress [compression-level] and evaluated in our code
We can start adding the
imagemin calls right in the controller but I'd much rather prefer a model for this. First, let's download a sample image to compress and place it into
/images/test.jpg. Also, add a
Note the following things:
fs.promises.access, we check if the
sourcePath-File exists. Technically, we're introducing race-conditions with that but that's fine for me.
- We're passing
compressImagefunction but only use
imageminis asynchronous so our
compressImagefunction needs to be
asyncaswell to call
await imagemin. We'll come to that later.
- Finally, we're printing out the result of imagemin with
updating our CLI controller
Then, we want to expand our CLI with a parameter that determines the destination to save the compressed image as. Our CLI will look like this then:
node run.js [sourceFile] [desinationFile] [--compress] [compression-level]. With this, we'll also refactor our code a bit so missing parameters are catched earlier:
Note the following things:
imageminis asynchronous (That means that we have to wait for imagemin to finish processing our image before we can actually say that it succeeded and furthermore process it), we also needed to change all functions upstream to be
async. You can find a nice article about asynchronous concepts on MDN
- I added a
checkArgsForErrorsfunction that adds up errors that might occur. When we start resizing, we can also move the check if the source file exists here
const [sourcePath, destinationPath, command, ...options] = args;,
argsare destructured into more meaningful variables that we can use in the switch.
Make sure to also update the controller function call in
You can now run our CLI with
node run.js ./images/test.jpg ./images/compressed/test.jpg --compress
If the source file can't be found, our CLI will print out an error just like this:
Wrapping it up
Today, we refactored our
cli-controller and added an asynchronous
compression-model that takes different options to pass it to
If you want to clone the project, you can: https://github.com/fschoenfeldt/ghost-compression
Thanks for checking out my guide series for writing an image compression app with NodeJS. If you have any questions, feel free to contact me via https://fschoenfeldt.de - Part IV is coming, very soon! x
Photo by Tim Mossholder on Unsplash