pagespeed
100/100

It's all about performance

Back at the beginning of 2017, the company I was working for was investing heavily to make their website faster and faster. The main goal was to increase their rank on Google. One of the subjects they were always talking about, was to reach the highest as possible on Google PageSpeed tool.

The tool itself is being there for a while, but I never cared that much about that matter. I was working more on wrapping up APIs and develop our AngularJS application, where the focus was on the logged-in user experience, so never really cared about SEO.

Anyway among the front-end developers we were always talking about the new cool technology, such as AMP and PWA. And of course, we were talking about how we would make our current public facing website perform well on Google Pagespeed.

Since then I started to dig into it, in my spare time. So I decided to take the challenge to rewrite my own website making sure I would reach 100 out of 100 on Google PageSpeed. More as a personal challenge, then really make it fly high on Google SEO results.

So, my website was developed from the day zero thinking about performance, accessibility and best practices to reach the highest score on Google PageSpeed, and I successfully did it, and here I will present you how I did it.

DISCLAIMER

The following post is way more about how I hacked my way through my website to reach the 100/100 result.

I will cover the most "tricky" parts of the Google PageSpeed because I really hope that you are doing the rest by default.

I will cut out of next posts the following:

Except for the "Reduce server response time", all other subjects are trivial IMO. And you totally should do it by default, no matter what you are developing to the web.

Let's talk about:

So, basically what Pagespeed want you to optimize here is the HTML file size, you can save a few bytes to the end user. If you are using node.js express, I would recommend you to check this package. You can use it on your express app like this:

        
var minifyHTML = require('express-minify-html');

app.use(minifyHTML({
  override: true,
  htmlMinifier: {
    removeComments: true,
    collapseWhitespace: true,
    collapseBooleanAttributes: true,
    removeAttributeQuotes: true,
    removeEmptyAttributes: true,
    minifyJS: true
  }
}));
        
      

And done! You are minifying your HTML files. You may be thinking right now, OK. But why are you talking about HTML minification and not CSS and JavaScript minification? I think HTML minification is trivial as CSS/JS. And I am talking about it in this post because you almost never hear about it. Not even when you start learning about front-end development, most of the people out there are teaching you to minify your website's CSS and JS. To be honest, before I start digging into PageSpeed I never really heard of someone doing it with HTML.

Moving forward to compression! Fine, I already read about gzip on its RFC, you also read Google's recommendations on their page about compression, where you can find useful links to your favorite web server, such as Apache, Nginx or IIS.

But you are super cool and you keep your website on Heroku. Where you don't have access to your web server configurations.

OMG, how can I compress my files?

Yeah, it's kind of bad for you to delegate a web server duty to your application. But, sometimes you need to do it, in my case, I just added the compression package on my express file as the following:

        
var compression = require('compression');
app.use(compression({ threshold: 0 }));
app.use(express.static('public'));
        
      

Pro tip: make sure to add the express.static() function AFTER the compression configuration, otherwise you won't serve your static files compressed.

And your compression is done. Nice and easy. ;)

Moving forward let's talk about "Prioritize visible content" and "Eliminate render-blocking JavaScript and CSS in above-the-fold content". They are kind differently, but they bounded on my website, and in many other cases it could be as well.

Even before you start thinking about how to properly tackle those issues, to "Prioritize visible content", you need to make one step back and rethink your page design. As much simpler the above the fold content looks like, easier is to prioritize visible content.

Two good examples one is my website https://stulzer.com/ and another one is Wundertax's website https://www.wundertax.de/.

What they have in common? The first thing you see when you land is a big frame with very small content on it. The amount of HTML and CSS code for it is so small that can be easily inlined on a <style> tag inside the <head> and at the moment the user loads the website, he will see the content styled. By doing that you will be prioritizing the visible content of your page.

For my website, the amount of CSS is so small, that I simply added the whole CSS on the <style> tag on the <head>, no need to worry about it. As I am using node.js for my website I could make it simply including the compiled .css file on the head.

I simply added on my _head.ejs partial the following:

        
<style media="all">
  <% include ../../public/stylesheets/main.css %>
</style>
        
      

Doing that I prioritize the visible content, and already eliminated render blocking CSS on above-the-fold content. Now let's talk about JavaScript. I fucking love JavaScript, the results you get using JavaScript on the client side are beautiful. But indeed you can block the page render if you don't use it properly.

First of all, if you are aiming to reach 100 out of 100 on PageSpeed avoid JavaScript for a simple landing page, or even use it with async attribute tag. Or even better, don't use any JavaScript at all.

But, this is inevitable right? We need some JavaScript here and there. What I would say is, avoid it, if you can't use the async attribute, if you have an intense JavaScript which may freeze the browser try to use it on a web worker, as I did in my blog. Yep, right here.

All pieces of code you are seeing here is colored by a JavaScript lib, that is loaded asynchronously, also rendered to the colored version asynchronously using Web Worker messages for each section containing code.

To achieve that I first had to add on my public directory the 'highlight.pack.js', the syntax highlighting library itself. Then I on my worker I load it, expect to receive an array of items I loop through those items I run the highlight js function to make the code highlight then for each item I post back a message to my worker with the id of the element and the new highlighted content. The code is simpler then explain it, take a look:

        
onmessage = function(event) {
  importScripts('/highlight.pack.js');
  event.data.items.forEach(function(item) {
    var result = self.hljs.highlightAuto(item.itemContent, [item.lang]);
    postMessage({'id': item.id, 'itemContent': result.value});
  });
}
        
      

worker.js

Then on the main.js file, we register the worker, grab all the items, post them to the worker, and listen to the messages from the web workers. The message will contain the element id and the new HTML that we want to replace the element that has this id. This new HTML will have the right classes to make the code highlighted. By the way, those are the same colors I used for my color theme for iTerm and Vim, you can check it out here.

And the only code I have on the main.js file is this:

        
addEventListener('load', function() {
  var worker = new Worker('/worker.js');
  var elements = document.getElementsByClassName('js-code');
  var items = Array.from(elements).map(function(item) {
    return {
      'itemContent': item.textContent,
      'lang': item.className.replace('js-code', '').replace(/\s/g, ''),
      'id': item.id
    }
  });
  worker.postMessage({items: items});
  worker.onmessage = function(event) {
    document.getElementById(event.data.id).innerHTML = event.data.itemContent;
  }
});
        
      

main.js

So, if you are willing to have JavaScript on the same page you want to achieve 100/100 on Google PageSpeed, first avoid using JavaScript, if is not possible add in the end of you <body> tag with the async attribute, if you have intense JavaScript tasks, try to fire up some Web Workers to help you out.

For now will be it, the next post I will talk about "Leverage Browser Caching" and I will have a surprise for you all. Tell me how hard was for you to reach 100/100 on your own pages? Specially adding Google Analytics script, to reach me try check my about section.