Asset Compression & the Impact on your Website Load Time
JavaScript and CSS files are an integral part of modern web pages. Due to the way web browsers load pages, the size of these assets can significantly affect your website load time.
This is becoming more of an evident problem in recent years with the explosion in popularity of front end frameworks like Angular.JS, React & Ember.JS. With these, a large part of your site or application’s logic is defined in JavaScript and executed after the page loads.
Median asset sizes over the last 5 years (data from httparchive.org)
There is an easy way to decrease the size of some of these assets: by concatenating and/or minifying them.
Concatenation
The main reason to concatenate your JavaScript or CSS asset files is to reduce the number of server requests that a browser needs to do. It may not seem like it, especially for static content such as JS/CSS, but server requests are costly.
There is a fair bit of overhead in each server request, a traditional HTTP/1 page load looks like the following:
- DNS lookup
- Establish connection to the web server
- Send HTTP request
- Wait for response
- Receive response
Steps 1-3, in an average page load, are generally fairly small and are usually a few hundred milliseconds. However, if you have 30-40 JS/CSS files per page, those milliseconds can add up very quickly.
So how do you fix this?
The simple solution, and the first that pops to mind, is perhaps to concatenate each of your JS and CSS files into two big respective files.
This, unfortunately, is not such a great idea for a couple of reasons.
- Giant files are bad
Firstly, having a giant file means that your web page will not render until the entire file has loaded. If your site relies quite heavily on JS or CSS—which most sites do these days—it’s going to look pretty bad or simple not work until your entire asset file gets pushed over the wire.
- Internet Explorer (9) is going to balk
IE9 has an unfortunate hardcoded limit to the CSS it can parse. It refuses to parse any more than the 4095 CSS rules per file.
This limit is particularly easy to breach with a concatenated file, especially if you use a pre-processor such as SASS or LESS as they generate quite verbose CSS.
Alright, how do you actually fix this?
Unfortunately, there isn’t a golden panacea that will give you a solution, you’ll need to handle things on a per-project or site basis.
Here are a few options:
- Concatenate based on asset priority
Some of your assets are just going to more important than others. Concat and load the more important ones before the others.
For example, say you built out your site using a number of third-party libraries and frameworks and have a fair amount of custom-built code. All the third-party library/framework (vendor) code needs to be loaded prior to any of your custom code.
What you can do in this case is concatenate all of your vendor code into a single a file (e.g. vendor.js) and your app code into another file (app.js).
- Categorise your assets
You can also split the app.js (or app.css) file up even further by categorising the contents of that file by its contribution to the page. For example, load all of the assets that render content above-the-fold prior to any of the other assets.
- Bless your CSS
A simple solution to getting around the IE <9 selector problem mentioned above is to use Bless. What this is does is analyse your CSS and then split it up into a new file prior to the 4095 selector limit. It’s almost like magic and can either run as part of your build pipeline or on the server via Node.JS.
In certain systems, such as Drupal (which we use extensively), there are modules that automatically do this for you as part of the CSS aggregation step. Our personal favourite is the Advanced Aggregation module which does it with a simple configuration setting.
- Components everywhere!
Another, more complicated option is to go down the route of turning your pages into collections of ‘components’. You can then use something like webpack to bundle these components up into discrete bundles which you load as required.
Minification
This technique complements concatenation well and lets you further reduce your asset load times.
The gist of this technique is that we strip out a lot of the cruft in your JS/CSS assets—such as comments and whitespace—to reduce asset footprints and thereby reduce load times. Browsers are just machines, they don’t necessarily care what your asset files look like, only that they are syntactically valid.
For example, here’s some un-minified CSS code from Normalize.css:
/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Change the default font family in all browsers (opinionated).
* 2. Prevent adjustments of font size after orientation changes in IE and iOS.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
The minified variant looks quite different:
/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
and:
Then simply run it against your CSS files. For example, to minify your style.css file into a style.min.css file:
becomes:
Then simply run it against your CSS files. For example, to minify your style.css file into a style.min.css file:
The difference is 0.44kb unminified vs 0.17kb minified, a 60% difference which is very significant.
Why shouldn’t you do it?
Before we delve into the various methods you can use to minify your code, there are reasons why you wouldn’t want to implement minification.
- Don’t use it for development (unless you have sourcemaps)
Minifying your assets makes finding problems extremely difficult when developing a website. You lose all visibility over how a certain bit JS behaviour is really defined as the minified source is not readable.
There is a way to get around this however and that is to use sourcemaps. These map your compiled, minified files to their original source files and are supported in most modern browsers.
- Don’t blindly use JS minifications on third-party or legacy code
JavaScript minification relies on your source code being syntactically correct. Minifiers can only do so much, fixing broken code is unfortunately outside their purview.
There’s a chance the minified versions of your code may simply not work. We highly recommend thoroughly regression testing your site after minifying any of your assets.
Warnings heard, now how do I do this?
The tools differ for both CSS and JS but they generally run as part of your development build pipeline. We at Sitback love Gulp and integrate minification into our standard frontend development workflow.
Alternatively, minification may already be built into your CMS of choice or there may be plugins that extend your CMS to support it. Some examples:
- Minifying CSS
We generally use the clean-css package to post-process our CSS files and minify them.
Using it directly is fairly simple and requires you to have Node.JS installed. First install it via npm:
npm install -g clean-css
Then simply run it against your CSS files. For example, to minify your style.css file into a style.min.css file:
cleancss -o style.min.css style.css
- Minifying JavaScript
Our favourite tool for JS minification is UglifyJS which we run using the default options.
This too can be installed and run via Node.JS and npm. For example to install the tool and minify a app.js file into an app.min.js file:
npm install -g uglify-js
uglifyjs app.js -o app.min.js
One more thing
Want to try some of these techniques out immediately but don’t want to go mucking around in your build pipeline or CMS just yet?
Just copy your JS or CSS onto http://refresh-sf.com/ and see how much faster you could make your site.