Achieving 100 Google points

Recently I have re-built my blog (hence the new life that has sprouted), not that you can tell. I spent a portion of last week moving away from Ghost to using Jekyll. With this I took the opportunity to improve the performance by utilizing Grunt as part of the build workflow. This allowed me to achieve a 100/100 rating on Google PageSpeed Insights.

100/100
All the Google points!

So, what's my secret?

Well its simple, do what Google says.

Here are the steps I took to get up to the 100 mark...

1. Use a static site

Using static sites (as opposed to dynamic sites) makes this much easier. As the HTML is fixed and not going to change based on what the user does or what data may be in a database you can ensure that what is rendered is in the best possible state.

I have used Jekyll for my Blog but I have heard good things about Middleman, Harp.js and Sculpin.

2. Be tappable

For any links, buttons, etc. on your pages that you want people to interact with make sure they can be pressed with a fat finger on a small touchscreen. This means to give grouped buttons enough space around them so the user can easily tap the one they want without inadvertently tapping the other and that links are roughly 2.4mm in height.

This one I have to keep fighting with. As new links appear on the page, Google sometimes decides some of them aren't big enough.

The following tips make use of Grunt, if you haven't used it before then be sure to read the getting started first.

3. Remove unused CSS

There is a great Grunt plugin called uncss that will remove unused CSS from your stylesheets, thus reducing the overall filesize. I found this to be mostly useful when applied to 3rd party stylesheets (such as bootstrap).

Example config


uncss: {
	dist: {
	    options: {
	      ignore: ['.center'], // Ensure these styles aren't removed
	      stylesheets  : ['css/screen.css'] // The stylesheets to check
	    },
	    files: {
	        'css/screen.min.css': ['*.html', '_layouts/*.html', '_includes/*.html'] // Output stylesheet and the pages to check against
	    }
	},
	bootstrap: {
	    options: {
	      stylesheets  : ['css/bootstrap.min.css']
	    },
	    files: {
	        'css/bootstrap.min.css': ['*.html', '_layouts/*.html', '_includes/*.html']
	    }
	},
	fontawesome: {
	    options: {
	      stylesheets  : ['css/font-awesome.min.css']
	    },
	    files: {
	        'css/font-awesome.min.css': ['*.html', '_layouts/*.html', '_includes/*.html']
	    }
	}
}

4. Shrink your CSS more!

Removing unused CSS is nice but there is still a lot of bloat that isn't required - spaces, line breaks & comments. The browser doesn't use any of this, so why bother sending it? The grunt-contrib-cssmin achieves this nicely. To keep files readable when developing we can have cssmin output the minified files as a *.min.css file, leaving the original intact. I don't use any JavaScript on my Blog but there is also grunt-contrib-uglify that can shrink down your JavaScript files in a similar way.

Example config


cssmin: {
    dist: {
        expand: true,
        cwd: 'css/',
        src: ['*.css'],
        dest: 'css/',
        ext: '.min.css'
    }
}

5. Get those images into shape

Images often make up the bulk of a websites total filesize.[citation needed] Just like with CSS we should also be reducing bloat from our images. grunt-contrib-imagemin can do this for us, with options to specify how much compression to apply. I left it at default and saw a rather sizable reduction with some images with no noticeable quality loss.

Example config


imagemin: {
    static: {
        options: {
            optimizationLevel: 3
        },
        files: [{
            expand: true,
            cwd: 'images',
            src: '**/*.{png,PNG,jpg,JPG,gif,GIF}',
            dest: 'images'
        }]
    }
}

6. Reducing time over the wire

When a web browser loads a site, it must first fetch the HTML file, read over it all and then fetch any associated resources (stylesheets, JavaScript files) causing additional calls back to the web server. This is just wasteful! Why make the browser ask for what we already know it needs? So, grunt-html-smoosher to the rescue. This handy little plugin will take HTML files and replace resource tags (e.g. <link>) with their content inline.

Example config


smoosher: {
    all: {
      files: [
        {
          expand: true,
          cwd: '_site/',
          src: ['**/*.html'],
          dest: '_site/'
        }
      ]
    }
}

7. Shrink whats left

So, we've reduced our CSS, our JavaScript (if we have any) and our images. We've event smooshed most of these into a single file. What could possibly be left? Why the HTML of course! So for our final trick we are going to use grunt-contrib-htmlmin to remove all spacing, line breaks and comments from our final HTML files.

Example config


htmlmin: {
    dist: {
      options: {
        removeComments: true,
        collapseWhitespace: true
      },
      files: [
        {
          expand: true,
          cwd: '_site/',
          src: ['**/*.html'],
          dest: '_site/',
        },
      ]
    }
}

Bonus - Getting the Green Padlock

As an aside I recommend giving this post about setting up SSL in nginx by Matt Gaunt. It walks through the process of getting a free SSL certificate and configuring nginx to make best use of it with SSL Labs test to validate the improvements

Conclusions

As you can see, it doesn't take a lot to improve the performance of websites. Pull all this together into an effective workflow and you don't even need to worry about it anymore. I have all my Grunt jobs, including one to build the Jekyll sites, as a post-receive Git hook. No more ftp/scp nonsense, no more remembering how to build my site, just code and push. Simple! 😄

If anyone uses a similar approach to their sites, or has ways to improve please