Image Optimization With Gulp


Easiest way to speed up a website? Image optimization. Hands down.
web-performance gulp

This is Ian.

A picture of my friend Ian

Ian

Ian doesn’t didn’t know about image optimization, and made a web site with big banner images that broke all of the most basic rules about putting images on a website:

  1. If it’s a photographic image without transparency, make sure it’s a jpeg.
  2. Make sure the image is the size you want it to be on the site, so the browser isn’t resizing it.
  3. “Optimize” the image.

As his friend, I couldn’t let this continue, so I decided to make him a gulp task that would handle all of this for him.

Make sure the image is the right file type

There is a lot that can be said about what image type to be used for which situation, but all we need to know today is if you have a “photographic” image (like something you would take with a camera), that you did not add any transparency to, you want to use jpeg.

I feel like this trips out a lot of developers, because the first thing they think about images is always:

JPEG is a “lossy” compression algorithm. I’m not about lossy images. I’m gonna use PNG! #lossless #TurnDown4What #blessed

And that is true. JPEG is a “lossy” compression algorithm, but digital cameras that cost thousands of dollars default too the format, so I think it is safe to say that it using it will not result in an image quality problem. Also, and more importantly, all the data it loses, makes the file comically smaller in size, and therefore makes your image load faster.

To convert any image to JPEG with gulp, I am going to use the gulp-image-resize package. The package uses ImageMagick and GraphicsMagick which will need to be installed on your machine, you can find instructions to do that here.

The plugin lets us convert file types pretty easily by just specifying the format, like so:

var gulp = require('gulp');
var imageResize = require('gulp-image-resize');

gulp.task('default', function(callback) {
    gulp.src('Path/To/Images')
        .pipe(imageResize({
            format: 'jpeg'
        }))
        .pipe(gulp.dest('dist'));
});

Serve scaled images

This is more important than it seems. You don’t want to send a file that has more pixels than the user is going to view, because those unused pixels are going to cost your page load time.

Luckily for us it’s pretty easy to specify which size image to serve for regular images with the img srcset attribute and for background images with media queries, the hard part is making all of the different size images.

In Ian’s case, he was using a 1920x974 image for his background… completely unnecessary unless your audience is all people with those ridiculous 5k iMacs. There are several schools of thought on what you’re largest background image size you should go with is. I typically go with 1500x1000.

I don’t know how I ended up at this default. I think because years ago when I was researching the issue I read a lot of posts about the necessity of going full HD with background images, some posts about how full HD doesn’t matter because CSS pixels are bigger than real pixels so you should go with 1200, and I just decided to split the difference and went with 1500.

To add resizing to our gulp task, we can specify width or height or both.

var gulp = require('gulp');
var imageResize = require('gulp-image-resize');

gulp.task('default', function(callback) {
    gulp.src('Path/To/Images')
        .pipe(imageResize({
            format: 'jpeg',
            width: 1500,
            height: 1000
        }))
        .pipe(gulp.dest('dist'));
});

Optimizing images

I am going to be honest with you, I don’t know what all exactly goes into image optimization.

I do know that most images have a ton of metadata that they don’t need to have (and you might not want them to have) when being used purely to make your website look prettier.

We can remove metadata from our image with the same gulp plugin, by specifying the noProfile option:

var gulp = require('gulp');
var imageResize = require('gulp-image-resize');

gulp.task('default', function(callback) {
    gulp.src('Path/To/Images')
        .pipe(imageResize({
            format: 'jpeg',
            noProfile: true,
            width: 1500,
            height: 1000
        }))
        .pipe(gulp.dest('dist'));
});

Image optimization can also do weird photo magic, where it takes into consideration how many colors are being used by the image, and removing the information about the colors that aren’t being used to make the file size smaller. I am not going to pretend to understand how that works, but I will pretend to be able to tell you how to do it with gulp.

For this, we need a new package: gulp-imagemin

It’s pretty simple to include in our current task, just pipe it in:

var gulp = require('gulp');
var imageResize = require('gulp-image-resize');
var imagemin = require('gulp-imagemin');

gulp.task('default', function(callback) {
    gulp.src('Path/To/Images')
        .pipe(imageResize({
            format: 'jpeg',
            noProfile: true,
            width: 1500,
            height: 1000
        }))
        .pipe(imagemin())
        .pipe(gulp.dest('dist'));
});

Results

Running our task on Ian’s original image of size 2.99M, we get an optimized image of size 131.74K. Nice.

An optimized and scaled version of the image in question

It even looks good scaled down

I encourage everyone to look more into image optimization and other web performance tactics. Some resources to get you started:

Oh, and don’t forget to checkout Ian’s site.

comments powered by Disqus