“Grunt” your way to frontend performance optimization
Clearly, performance is (and should) not (be) an after-thought anymore. When web developers create websites, performance can influence the success or failure of a web product. We’ve been hearing from leading performance advocates like Ilya Grigorik that speed is a feature and should not only be thought of just before a product hits production but rather as an essential part of the web product development cycle.
For example, instead of minifying and concatenating CSS and JavaScript files manually, tools and processes are out there that can help and put these performance tasks into an automated workflow, and more importantly right from the beginning of a product development cycle.
I’ve been using Maven to run most of the automated performance optimization at work, however I’ve been always interested in using Grunt for the same purpose. Grunt is a task runner, created for web products, based on JavaScript that can be leveraged to make performance part of the deployment process.
In today’s blog post I will be sharing some of the plugins for Grunt that can be used to speed up and automate performance optimization. At the end of the blog post, I will present performance results that will show that frontend optimization (FEO) can be fun and easily be automated to cut page load time.
Google’s “Make the Web Fast” team recommends frontend best practices as well as Steve Souder’s “High Performance Web Sites” outlines rules that can be applied for FEO. I decided to pick two of Steve’s rules “Make Fewer HTTP Requests” and “Minify JavaScript” (and CSS, HTML) by using Grunt plugins that can help automate those specific rules. So here it goes.
Note: The post assumes that you’ve worked with Grunt before and know how it’s been installed, and how to install plugins (I won’t go into details, however links at the bottom will help you)
“Let’s grunt it up”
(All plugin headings in this post are clickable links to their appropriate pages)
grunt-montage
Montage helps you sprite images to reduce HTTP requests. You will need ImageMagick to be installed. Alternatively, you can also try out grunt-spritefiles.
grunt-usemin
This plugin is useful when you want to develop and debug a version of your site that doesn’t use the minified and concatenated version of your JavaScript or CSS files. A comment blocks is wrapped around your JavaScript and CSS assets that will be concatenated to your destination after deployment.
<!-- build:js js/magic.min.js --> http://js/1.js http://js/2.js http://js/3.js http://js/4.js <!-- endbuild -->
will become
http://js/magic.min.js
You can use grunt-processhtml instead.
grunt-closure-compiler
Alternatively you could use grunt-closure-compiler instead of combining concat and uglify and cssmin for JavaScript and CSS files.
grunt-contrib-uglify
Uglify and concat go almost hand in hand and should be used together, the concat plugin first makes sure to combine all defined JavaScript files. Uglify only works on JavaScript files. It minifies all code in a one line block of code. Use cssmin for CSS files.
grunt-contrib-cssmin
Same logic and idea than uglify, once your CSS files are all concatenated, use cssmin to shrink several lines of CSS code into one single one.
grunt-contrib-concat
Combine CSS and JavaScript files with this plugin, it allows you to reduce your HTTP requests for each and every file to just one combined file.
grunt-contrib-imagemin
imagemin minifies JPG and PNG images. It’s a handy Grunt plugin if you don’t know if the assets you got handed from your designer (or yourself) are optimized for web yet. By using this tool, you have the piece of mind that you use image files in an efficient way. Alternatively, you could use grunt-smushit, it’s based on Yahoo’s great smushit tool that is available in the YSlow plugin for several browsers.
grunt-image-embed
This plugin encodes images as base64 and leverages the technique of data URIs for images, something that can be used inline with CSS to reduce HTTP requests and hence reduce page load time. I’ve written a blog post where this is explained in more detail.
grunt-htmlcompressor
This plugin is using htmlcompressor tool to minify and compress HTML files. The options parameter is handy to tweak your compression, my example uses compressJS and preserveServerScript to also compress inline JavaScript and server script tags in case I wanted to include some SSI code.
spofcheck
Use grunt-exec to run the SPOFcheck. An excellent tool to identify bad 3rd party scripts includes, developed by the eBay team. I didn’t include the scripts asynchronously, hence SPOFcheck complaints to avoid SPOF.
“It’s Magic” Sample Page
I created a simple page themed “It’s magic” where I applied all mentioned plugins. You can find the files including Gruntfile.js here. Please note, I intentionally didn’t put a lot of effort into the styling (It is supposed to look as simple and cheesy as it feels to you)
In a nutshell, the page has a logo, uses JQuery from the Google CDN, includes a simple JQuery gallery with previous and next buttons. Simple JavaScript and CSS files are being used.
“without/magic.html”
The logo is a png logo, the images are not optimized. There are several CSS and JavaScript files that are all individual being included, not minified nor concatenated.
“with/magic.html”
This file is the one that Grunt will create for you. Visually, the file doesn’t look that different, besides the fact that the title has changed….see yourself
Below are screenshots of the two pages (and links) side by side, the one on the left before Grunt tasks were applied. The right one shows the page after Grunt tasks were applied. For the user they both look the same (except for the heading).
without/magic.html
with/magic.html
Can you spot the differences?
- The logo was being transformed into a data URI
- The title has changed from It’s not magic to It’s magic
- The local CSS and JavaScript files were being minified and concatenated
- The HTML was being compressed, comments were taken out automatically
- The next and previous buttons were converted to a sprite file
- On build, SPOFcheck was applied and gave us the following warnings so we could address possible SPOF issues
Let’s take a look under the hood
Here are the waterfalls for both versions:
Without magic
WebpageTest Results
I ran WebpageTest for both files with 9 runs for IE8 with a DSL connection to retrieve the median. Here are the performance results:
- HTTP requests dropped by ~48%
- Page load time (PLT) dropped by ~10%
- File sizes dropped by ~10%
Even if those numbers are not that high (mostly due to the simplicity of the experiment), it shows that Grunt can help you automatically optimize your deployment process.
As you can tell by the sample code, there are many mix and match options available, depending on the magnitude and granularity of your page structure. Nevertheless, this little sample shows how to use Grunt to optimize performance and to illustrate what is possible. Feel free to use the code as a starting point, and tweak or customize it to your likings.