Once my site was up and running in Jekyll, it was time for some improvements. It wasn't running as smoothly as it could, and here is what I've changed.
Articles in this series:
- Migrated from Ghost to Jekyll
- Migrating content from Ghost to Jekyll
- How I set up this blog on Jekyll
- How I improved my Jekyll setup (this article)
- How I improved my Jekyll SEO
- Fixing my content after migrating to Jekyll
Speed up build process
Jekyll isn't the fastest static site generator, and I'm okay with it. If it takes a minute or two for me to publish my latest article, it's perfectly fine. I'm not in a rush. But being a developer at heart, I realized there are a few things that I could do to decrease the build time.
In the beginning →
I started with building my site with Jekyll v3. Building the site using the base setup with a couple of plugins enabled was taking roughly 90 seconds. Not a world's speed record, but good enough for me.
All build times are based on the times reported by Netlify deployments.
Merge liquid templates includes ↑
Looking for information about how you can improve Jekyll's build times, I learned that inefficiencies in liquid templates can have a noticeable impact on the build times and that you should combine them where possible. After merging a few includes I noticed a second or two improvement of the build time, but nothing more than that.
Added AMP pages ↓
After switching from Ghost to Jekyll I lost AMP pages. There are different opinions on how important it is for SEO. Either way, I wanted to offer a lightweight alternative version of my content. After enabling AMP on my site, my build time increased to 155 seconds.
Install Liquid C ↑
The first thing that I've done, to decrease my site build times, was to install liquid-c. It's a c-based implementation of the liquid parser that's faster than the one used by Jekyll by default. Unsurprisingly, my build time decreased to ~120 seconds.
Added extra AMP pages filters ↓
To further enhance generating AMP pages, I added filters for processing scripts and iframes. Unfortunately, that increased the build time to ~130 seconds. Later I found out how I could speed up the generation of AMP pages by combining multiple filters into one and decreasing the number of times filters had to parse each page's HTML.
Update to Jekyll v4 ↑
Looking for other ways to speed up my build times, I found out that Jekyll v4 was released and had some significant performance improvements. After trying it out, I haven't noticed any side-effects other than the jekyll-target-blank plugin being incompatible.
Switching to Jekyll v4 brought down the build time to ~70 seconds, which is almost half of the previous build time. But it's not all thanks to Jekyll v4. Later I found out, that the target-blank plugin has a significant impact on the build time as it post-processes all generated HTML files to decorate hyperlinks in them.
Switch to CommonMark ↑
Another optimization that I've applied was switching to the CommonMark markdown parser instead of the default Kramdown. While I noticed a slight build speed improvement, I also noticed that most likely it was by my code snippets no longer being highlighted. In my setup, I was using the Rouge highlighter, which enriches code snippets with additional markup when parsing Markdown. Without Rouge, of course, the build was faster, but also my code was not being highlighted. I didn't want to use Prism or other client-side highlighters to speed up loading the page for my visitors. While investigating the CommonMark parser, it turned out that support for Rouge was added, but that version of CommonMark wasn't released yet. So to use it on my blog, I had to switch from using the published gem to point to the GitHub repo instead.
Combine AMP filters ↑
As I mentioned earlier, I noticed that the AMP generator used several separate filters to post-process the generated content and ensure that the generated AMP pages matched the AMP spec. In this setup, each filter was processing the page's HTML by itself. So to speed things up, I decided to combine the filters into one, have them parse HTML of each page only once and then apply all modifications. This step brought the build time to 67 seconds.
Re-introduced target-blank ↓
I wanted to bring back the target-blank plugin to have external links automatically open in new tabs but also to isolate my site from external sites I link to. After bringing the plugin back, the build time increased to ~100 seconds. While it's acceptable for me, I'll be on the lookout for other build time improvements.
Extra: for local builds, exclude assets ↑
When writing new articles or updating my blog, I like to preview my changes, before pushing them to the repo. For that, I need just a few recent articles which I can build using:
bundle exec jekyll serve --limit_posts 10
I noticed, that still, even just for 10 posts, the build takes ~20 seconds. Then I found out, that on every build, Jekyll copies all assets to the output folder. In my case, that means copying over 5600 files with a total of roughly 400MBs. On. every. build. So to avoid waiting, I created a copy of the
_config.yml file which I named
_config_dev.yml and in which I've added:
exclude: - assets/images keep_files: - assets/images
To use this config file, I execute:
bundle exec jekyll serve --limit_posts 10 --config _config_dev.yml
The same build is now done in ~4 seconds!
Whenever I add a new image, all I need to do is to copy this one image, which I can conveniently do calling:
cp -rn ./assets/images ./_site/assets/
which recursively copies all images skipping the ones that already exist.
In this article, I walked through the different steps I've taken to set up my blog and keep the build times as low as possible. In the following articles, I will tell you more about how I configured Jekyll to improve SEO and how I work when writing new posts. Stay tuned!