Modern image formats with Gulp

Early on in my development workflow process I wrote about optimising images the easy way.  Image optimisation can make a really big difference, especially now that it appears to be obligatory to have a huge “hero” image section at the top of every website with a slider of huge high-resolution images.

If you’re on WordPress then I’d thoroughly recommend ShortPixel as an excellent plugin which seamlessly provides image optimisation.   I’ve written about this plugin/service in detail in my aptly named image optimisation with ShortPixel post.

However, if you’re building a website the “hard” way (not hard in my opinion, thanks largely to Gulp) then you shouldn’t miss out on easily using modern image formats, like WebP.

According to Google, who created this image format…

WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, webmasters and web developers can create smaller, richer images that make the web faster.

They’re approximately 25% of the size of PNGs and JPGs, depending on the image type and compression/colour settings, but in my experience can be much better than that, especially for logos with flat designs.

So how can we get these great benefits?  First we need to install a new plugin; gulp-webp

npm install --save-dev gulp-webp

And then we need to require it (unless you’re automatically requiring plugins)…

var webp = require("gulp-webp");

Then if we take the example from the previous optimising images the easy way post (but update it to Gulp 4)…

var img = function() {
  return gulp.src(["img/*.png","img/*.jpg"])
    .pipe(imagemin())
    .pipe(gulp.dest("build/img"));
};

We need to create a duplicate task that’s going to handle our WebP conversion, something like this…

var webp = function() {
  return gulp.src(["img/*.png","img/*.jpg"])
    .pipe(webp())
    .pipe(gulp.dest("build/img"));
};

This actually uses the imagemin plugin, the same as the gulp-imagemin plugin we used for the original task.  It can also support Tiff and WebP (compressing existing ones) but my example focuses on PNG and JPG.

Don’t forget to make sure that you’re adding this to one of your exported tasks, probably in parallel with the original “img” task.

You’ll also need to change your HTML to include the new images in a way that falls back in case the user is using a browser that currently doesn’t support WebP images (*cough* IE *splutter* Safari *cough*).

So you may have had an <img> tag something like this before…

<img src="img/git.png">

Now it will need to look something more like this…

<picture>
  <source srcset="img/git.webp" type="image/webp">
  <source srcset="img/git.png" type="image/png">
  <img src="img/git.png">
</picture>

This structure means that the browser will select the first image in the list that it supports, based on the “type” attribute.  And if it doesn’t support the <picture> tag at all then it will still see the <img> tag and therefore work as it did before.  Graceful degradation at it’s finest.  Just be careful that if you have any rules in your stylesheet that target the <img> tag directly, these may need to be reviewed with the new markup in mind.

This is all covered in detail in my Optimising your website: A development workflow continued with Gulp 4 course.

You may have noticed that I also removed the gulp-newer call from the original example – this is because there are two parallel image tasks now, so you can’t compare timestamps otherwise only the first task will work.  I did look and splitting and merging streams so that this can be done in a single task, but I couldn’t get any of the existing plugins to work properly with Gulp 4.  If I get it working, I’ll write a follow up post to detail how I got this working, as one images task would certainly be more ideal, and allow us to speed it up by only optimising the new ones.