Jekyll Speed Improvements

This blog is based on jekyll a static site generator that takes my markdown files and generates static html, css, JavaScript and all the other magic that makes this beautiful blog. I love this setup mainly for two reasons. Firstly, I write in markdown so my content is independent from the platform. Secondly, I like static sites. It is so much harder to create an inflated and slow page where the visitor has to wait for seconds until the page is loaded after each click. If you put in the extra effort it is possible to have sites served at lightning speed.

Browser caching

One of the most important things is to save the browser some work and let it reuse some resources. How often do you change your css or your JavaScript? Propably quite rarely. So let the browser reuse it’s files and let it know when to reload. One way is to set the cache header to “indefinitely” and add a cachebuster whenever you change the file.

I added this lines to the apache configuration …

<FilesMatch "\.(jpeg|jpg|png|js|css)$">
    Header set Cache-Control "max-age=31536000, public, s-maxage=31536000"
    Header set Pragma "cache"
</FilesMatch>

… and added a small Cachebuster tag to jekyll.

require 'digest/sha1'

module Jekyll
  class CacheBuster < Liquid::Tag

    def render(context)
      rendering_time = context["site"]["time"]
      "#{Digest::SHA1.hexdigest(rendering_time)}"
    end
  end
end

Liquid::Template.register_tag('cachebuster', Jekyll::CacheBuster)

This way I can easily create a seemingly random string based on the current time. It basically just takes the site.time (for example 2020-05-10 17:20:37 +0200) and calculates the sha1 from it (for example e7ac651a89cedb959848aebc45f56604d91a22e7).

We can then append this cachebuster to the css url for example.

<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}?version={% cachebuster %}">

But it is possible to get even better than this. Don’t load external js and css files at all.

Inline CSS and JavaScript

Wait, I thought inlining CSS and JavaScript is a bad thing1?! Generally speaking that is true. In my case the CSS and JavaScript is so small that the overhead of a seperate request is not woth it. Currently my CSS file is about 200 bytes and the overhead of a HTTP request is about 500 bytes to 1KB2 and my js is barely even there. Inlining is not always the best solution but it might be.

I decided to inline my .css and .js file. In order be able to write in scss and have my scss in seperate files I let jekyll do the heavy lifting.

I created a new _includes/inline.scss

@import "../_sass/main_sass_file";

… and replaced my old link to the stylesheet …

<link rel="stylesheet" href="{{ "/assets/main.css" | relative_url }}?version={% cachebuster %}">

… with this code to inline the css.

<style type="text/css">
    {% capture include_to_scssify %}
      {% include inline.scss %}
    {% endcapture %}
    {{ include_to_scssify | scssify }}
</style>

Minify your CSS and JavaScript

Speaking of scss. If you use scss or sass compressing your css is as easy as configuring it in the _config.yml.

sass:
  style: compressed

Minifying HTML is not as easy. I use this script by Anatol Broder with the folowing configuration. But be aware. For my blog it increased generation time from about 1.8 seconds to about 3.2 seconds.

compress_html:
  blanklines: true
  comments: ["<!-- ", " -->"]

Reducing image filesize

jekyll-compress-images is a great tool to losslessly reduce your image filesizes. I am using it with the following configuration.

imageoptim:
  skip_missing_workers: true
  nice: 5
  threads: 4
  svgo: false

Additionaly, make sure you don’t use oversize images.

The Outcome

Using all these methods (and some more) I was able to get a close to perfect lighthouse and PageSpeed Insights rating. Though you should use your common sense when checking these tools for issues on your site, they provide some great indicators. And it is always configming to see the green circles. PageSpeed Insights result Lighthouse Results