PageSpeed Insights and Ghost - Part 2

In part one, I concentrated on updated the server settings for my Ghost blog. In this article, I will handle the theme itself. Note at the time I write this my current version of Ghost is v0.5. There has been updated to the default Casper theme since this release so I plan on going back and updating this article after I upgrade to the newest version. Also, I will make this available on GitHub. Ok, let's get busy....

Getting setup

The first thing i did was to make a copy of the Casper theme folder. I renamed the folder to Gary ( I'm real original ) and placed that in Ghost's themes folder. However, before Ghost can recognize the new theme, I will need to restart the Ghost service on the server.

[sudo] service restart ghost

Now, I have my own theme to work with going forward. But first, let's take care of some other things first.

Optimize Images

Well, go figure... my logo image is not optimized. So I ran it through PNG Guantlet to compress it. I re-uploaded it to the server, re-ran the tests, and presto! Optimize Images no longer appears on my list! Five down!

  • Optimize Images

Now we can concentrate on our theme files.

Dealing with JavaScript

I didn't realize that out of the box, Ghost inludes three javascript files none of which are minified out of the box. They link to an unminified version of jquery (required for Ghost to run), fitvids.js (for showing responsive videos) and index.js (your "app" code).

To "fix" my problem with jQuery, I simply downloaded the minified version and overwrote the existing file located in the /core/shared/vendor/jquery folder. I then took the contents of fitvids.js, index.js and my Google Analytics code combined those into a simgle file. I then minified the file and placed it back in the themes asset folder.

We can now mark another item off the list:

  • Minify JavaScript

Minify the CSS

This was extremely simple. I grabbed the file from the server, ran it through cssminifier and put the updated code back out on the server. Easy peezy.

  • Minify CSS

Modifying default.hbs

Now that I have the JavaScript, CSS and images taken care of it's time to modify the default.hbs file. This file is the base "page" for every page of a ghost website. Modifications to this file affect almost every single public page.

In the head area, I wrapped the links to the stylesheets in a noscript tag. This prevents these files from being loaded unless javascript is disabled. Instead of directly linking to the files, we are going to use JavaScript to load these files ( including our javascript file ).

<noscript>
  <link property="stylesheet" type="text/css" href="/assets/css/screen.css?v=f27d5806b9" />
  <link property="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Noto+Serif:400,700,400italic|Open+Sans:700,400" />
</noscript>

Let's add the code needed to load these files. I use loadCSS and loadJS from the Filament group to accomplish this task. Simply add these scripts inline and call them. Super simple.

document.addEventListener( 'DOMContentLoaded', loadFiles, false );

function loadJS( src ){
  "use strict";
  var ref = window.document.getElementsByTagName( "script" )[ 0 ];
  var script = window.document.createElement( "script" );
  script.src = src;
  ref.parentNode.insertBefore( script, ref );
  return script;
}

function loadCSS( href, before, media ){
  "use strict";
  var ss = window.document.createElement( "link" );
  var ref = before || window.document.getElementsByTagName( "script" )[ 0 ];
  ss.rel = "stylesheet";
  ss.href = href;
  ss.media = "only x";
  ref.parentNode.insertBefore( ss, ref );
  setTimeout( function(){
    ss.media = media || "all";
  } );
  return ss;
}

function loadFiles() {
  loadJS('/assets/js/scripts.min.js');
  loadCSS('/assets/css/style.min.css');
  loadCSS('//fonts.googleapis.com/css?family=Noto+Serif:400,700,400italic|Open+Sans:700,400');
}

And with that, we have killed off yet another area.

  • Eliminate render-blocking JavaScript and CSS in above-the-fold content

Unfortunately, we now see the website load and then see the styles get applied. This is called FOUC (Flash Of Unstyled Content).

Killing the FOUC

To get rid of this, we need to add just enough CSS in a style tag to render the "above the fold content". This was probably the hardest part of the entire process. If you are a fan of nodejs (which I am), there is a tool created by Addi Osmani called critical. It is designed for doing this sort of thing. I, personally, had a hard time trying to get this to work with the default.hbs. I finally gave up and did it the hard way by literally just inspecting the page and getting the classes I needed.

I then placed these styles in a style tag in the head of the template file. And it worked. It took a little adjusting here and there but I got it to work.

  • Prioritize visible content

Conclusion

After all of these changes, did I accomplish my goal? Yes, I would have to say I did.

Here is the score on Mobile now:

Here is the score on Desktop:

And, lastly, the score on User Experience:

Not bad at all! The time and effort needed to do this was actually pretty minimal. I got it all done in about four or five hours. Well worth it in the end.

Until next time!
-G