This is the second part of this article that covers some tips on how to improve your website loading speeds. On the first part I've shown you how to use Gulp, a JavaScript task-runner, to automate those tedious tasks like minify and concatenate your files.

At the end of the first part we could see that the score on PageSpeed Insights was a lot better but still had room for improvement. That's what I'm going to address in this second part in order to get that 100% score!

Page structure

For a long time I thought that the script and link tags declarations should be done inside the head. And that makes some sense, it's like requirements for my webpage - I need this stuff for the page to work properly. Unfortunately that might slow down quite a bit the loading speed.

When the browser start rendering the HTML file and hits a script tag, it will only continue rendering after executing the whole JavaScript file. That's because JavaScript can manipulate the DOM and CSS. The scripts and stylesheets don't actually need to be inside the head tag, we've been doing that way mostly out of tradition, but the script is executed wherever is found on the document.

So, let's change our script and link tags to the bottom of the document, just before the body tag.

<html>
  <head>
    ...
  </head>
  <body>
    ...

    <!-- script and link tags here -->
  </body>
</html>

CSS can change the DOM too, but these are a little bit trickier, because, when you add the CSS files in at the end of the document, you can start seeing the whole page structure without any styles, and then in a flash moment you get all the CSS and the page get's back to normal. What I've done is to set the body opacity=0 and then on the CSS file put it back to 1, so the page will only show up after the browser finishes rendering the CSS file.

You can inline the styles on the HTML files (using the style tag), but that will only work if you have small amounts of CSS. You can inline above-the-fold (before the body closing tag) the most important parts of your CSS, and load the remaining CSS using JavaScript. The problem with this approach is that it will only load the CSS if the browser allows to run JavaScript.
So, in this case, only use it if it works for your website. There are other solutions for this, each one has their own pros and cons.

<html>
  <head>
    ...
  </head>
  <body>
    ...

    <script>
      var cb = function() {
        var l = document.createElement('link'); l.rel = 'stylesheet';
        l.href = 'css/semeano.min.css';
        var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
      };
      var raf = requestAnimationFrame || mozRequestAnimationFrame ||
        webkitRequestAnimationFrame || msRequestAnimationFrame;
      if (raf) raf(cb);
      else window.addEventListener('load', cb);
    </script>
  </body>
</html>

There's also another issue. This way our gulp-useref module won't be of much help, since it won't be able to change automatically the href from our source CSS files to our minified and concatenated single file. I don't know if there's a Gulp module that does that. If there is, let me know in comments.

Server configurations

If you have access to the server configurations there's a couple of things you can do to improve performance: caching and compression.

Caching

Caching files allows the browser to keep local copies of the requested files for a certain period of time. This way the browser don't have to download them all the time; it will just get them from the cache, making it load faster.

When the browser asks for a file to the server, that connection will return a header with information about that particular file. One of the fields of the header is Cache-Control. This field tells the browser if it should cache the fime and for how long.

There isn't any rule when it comes to how long should you be caching files, that will depend on the changes you make to your website. But as an example I can tell you that, if you use HTML5 Boilerplate the .htaccess file that comes with it has the following rules:

  • CSS and JS: 1 year
  • Images: 1 month
  • HTML: no caching

The .htaccess file contains this rules, but mind that this only works if you're using Apache as your web server. If you're using nginx or lighttpd you have to make the changes directly on the configurations file.

When analysing the PageSpeed Insights results, there was no cache-control header for the SVG file. I'm using lighttpd on my server, so I opened the configurations file (lighttpd.conf) and added a line, on the virtual host configuration for my website, that set the cache-control header to SVG files with a max-age of 1 month.

expire.url = ( "/svg/" => "access plus 1 months" )

After restarting the web server I made a simple test to make sure it was working. Just opened an "incognito" window, with the Developer Tools on the network tab and loaded the website. Here's the result for the SVG file:

Cache-control for SVG file

You can see on the Headers tab the Cache-Control field with

Cache-Control: max-age=2592000

that is the number of seconds in 30 days.
Check the documentation of your web server to know how to properly configure them accordingly to your requirements.

Override caching

In case you want to make changes to any of these files before the cache expires, you need a way to force the browser to download them. Since HTML, most of the time, isn't cached, when the browser is reading it and sees a file that he doesn't have in cache it will download it, showing this way the latest changes on the webpage.

An easy way to do that is to change the name of the files you want to force the download, so instead of referencing "semeano.min.css" I could name it "semeano.v2.min.css".

You can use gulp-rev-all and pipe it on your Gulp tasks in order to do this automatically. This Gulp plugin will create a copy of the files with a different name, and it will export a manifest file with the name changes, like this:

{
  "img/logo.png": "/img/logo.1b4f9424.png",
  "css/common/common.css": "/css/common/common.a3096bdf.css",
  "css/main/main.css": "/css/main/main.002ab92e.css",
  "js/common/common.js": "/js/common/common.7c0e6e56.js",
  "js/main/main.js": "/js/main/main.687fa3e5.js"
}

Then use this file to replace the paths with the correct filenames. You can do it on the server side, in case you're using a backend language like PHP, or you can use another Gulp plugin to handle that for you, like gulp-rev-replace.

Compression (GZip)

By compressing your files you will be saving bandwidth that will lead to faster downloads. When the browser makes the first request of the page contents to the server, it will tell if it supports compression or not. If it does and the web server is configured so that it can send compressed data, it will do it so. Otherwise the server will send all the data uncompressed. With this change alone you can save up to 80% in bandwidth.

Here's how you can turn on GZip on your web server. For the Apache you can simply add this to your .htaccess file:

<ifModule mod_gzip.c>
  mod_gzip_on Yes
  mod_gzip_dechunk Yes
  mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
  mod_gzip_item_include handler ^cgi-script$
  mod_gzip_item_include mime ^text/.*
  mod_gzip_item_include mime ^application/x-javascript.*
  mod_gzip_item_exclude mime ^image/.*
  mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</ifModule>

If you're using nginx:

gzip on;
gzip_comp_level 2;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/    javascript;    

# Disable for IE < 6 because there are some known problems
gzip_disable "MSIE [1-6].(?!.*SV1)";

# Add a vary header for downstream proxies to avoid sending cached gzipped files to IE6
gzip_vary on;

And if you're using lighttpd:

# Add mod_compress to your modules
server.modules  = (
  ...
  "mod_compress",
  ...
)

compress.allowed-encodings = ("gzip", "deflate")
compress.filetype = ("text/plain", "text/html", "text/javascript", "text/css", "text/xml")

# Don't forget to create a cache directory and add the path here
compress.cache-dir = "<your cache directory>"

In my case, the web server had the gzip compression on, but it wasn't compressing svg files so I had to add it to the file types to compress.

compress.filetype = ( ..., "image/svg+xml")

Note: don't forget to restart your web server after any change to the configuration file.

To verify that the GZip compression is actually working on the SVG file I opened again a incognito window with the Developer Tools, and made a before and after comparison.

Before:

Size: 4.4KB
Content: 4.1KB

Before

After:

Size: 280B
Content: 4.1KB

After

That's more than 94% less! With just one small tweak on the web server configurations!

Conclusion

Now the moment of truth. What's the PageSpeed score?

Mobile - 100% score

Desktop - 100% score

I hope I could help you making your websites faster and setup a work environment so you can keep all your future websites or webapps fast without much effort.

Feel free to share this guide on Twitter and Facebook if this was helpful to you. Also, if you have ideas and tips for improving website speed, let me know on twitter.