Modernising my Blog Part 1: Tools

This site has been sitting around for a while collecting dust, so it’s probably time to go through it and do a bit of modernizing. There are some older tools and technologies being used, in addition to some practises that I just don’t do any more, and I think my personal site should reflect the professional techniques I employ. I might as well find out if I’ve improved build times too, so between steps I’ll run bundle exec jekyll build to get an idea of how much it’s changed. Let’s get cracking!

Update Ruby

The blog is hosted on Netlify, and built using Jekyll. Since this site was started a while ago I’m still using Ruby version 2.3.3. My local dev machine uses rbenv for Ruby version management, so switching versions isn’t an issue. I’ve gone for 2.6.2 as this is the default Ruby version in Netlify’s build image, so using it instead of something newer (such as Ruby 2.7.0) should save installation time during builds.

Update Jekyll

My static site generator, Jekyll, is currently sitting on version 3.3.1. Since then a new major version has been released in 4.0.0, so it’s time to upgrade. Change the Jekyll line in Gemfile to read:

gem 'jekyll', '~> 4.0'

Then run bundle update.

Once updated the gems config entry needs to be updated to plugins (or grouped in Gemfile inside a jekyll_plugins group). Switching to 4.0.0 has brought the build time down from 30s to 25s, most likely due to some performance improvements and the new caching system (for subsequent builds). With that done it’s time to install a couple of other performance-enhancing gems.

Add liquid-c

liquid-c is an optional gem for Jekyll, but when you include it then template parsing gets a lot faster. I see no reason not to do this so let’s go ahead:

bundle add liquid-c

That’s it! Build times are now down to 19s after caching (21s cold).

Use CommonMark

Jekyll can be fast, but there’s a faster plugin for converting Markdown than the default Kramdown parser. That plugin is jekyll-commonmark, which also has the advantage that it uses the CommonMark standard for Markdown. I’m a fan of standards, so let’s install it:

bundle add jekyll-commonmark

Once installed, change the markdown config option to CommonMark and the build gets another second faster or so (admittedly this one has been harder to confirm, local builds do fluctuate slightly). To ensure that inline HTML inside Markdown files are converted properly then a couple of options and extensions are need to be set for CommonMark in Jekyll’s config file:

commonmark:
  options: ["SMART", "UNSAFE", "GITHUB_PRE_LANG"]
  extensions: ["table"]

The UNSAFE option allows HTML to be parsed properly, and the SMART option uses better punctuation in text. GITHUB_PRE_LANG adds classes to code blocks do that they can be styled like normal terminal/IDE output (that’s still to come).

Add jekyll-postcss

When I updated Jekyll I got a warning that Ruby Sass was officially end-of-life. Thankfully, I was already planning to remove it and use PostCSS instead. I use PostCSS professionally, and like being able to write modern CSS and not have to worry about which browsers support it. postcss-preset-env handles the polyfills and is clever enough to only polyfill features as required.

Thankfully there’s a gem called jekyll-postcss that adds PostCSS support, so let’s add it, then convert the Sass to CSS:

bundle add jekyll-postcss
yarn add postcss-cli postcss-import postcss-preset-env

Converting the Sass to CSS is straightforward, but tedious, and involves changing the extension to .css, removing any variables (using custom properties rather than inlining), and adding ampersands (&) to nested selectors. So something like this:

$mainColor: #f00;

.main {
  .second {
    color: $mainColor;
  }
}

Becomes:

:root {
 --main-color: #f00;
}

.main {
  & .second {
    color: var(--main-color);
  }
}

Now that PostCSS are postcss-preset-env installed, octopress-autoprefixer is no longer needed.

bundle remove octopress-autoprefixer

A .browserslistrc file is required to tell postcss-preset-env which browsers to target. I’m interested in any browser with more than 1% usage globally, so > 1% is all that’s needed in there.

PurgeCSS

It’s nice to not serve CSS that won’t be used, so let’s strip that out automatically using PurgeCSS.

yarn add @fullhuman/postcss-purgecss

postcss.config.js then needs to be updated to make PurgeCSS check the HTML in our jekyll directory and remove the styles that’s aren’t being used anywhere:

const purgecss = require('@fullhuman/postcss-purgecss');

module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-preset-env')({
      features: {
        'nesting-rules': true,
      },
    }),
    purgecss({
      content: ['./_site/**/*.html'],
    }),
  ],
};

PurgeCSS ultimately hasn’t removed much as the site is all handrolled CSS (I didn’t want to use a framework), but it’s also nice to know that if I don’t leave something in by mistake it will get whipped out during builds.

Conclusion

Overall I’m happy with how the site is looking under the hood. I’m no longer using Sass/SCSS, my packages are up to date, and everything is building a lot faster than it was. This puts me in a good position to start updating the site’s CSS and markup, as well as add some proper asset management, which up until now has been sorely lacking…