WordPress to Jekyll part 6 - A faster build

My site goes back to 2004 and is reasonably sized but not massive even with the comments, so waiting 30 seconds for a change to reflect is disappointing.

I investigated several options and ended up using a few in combination, skipping others and holding out for one.

Incremental build

Launching with the --incremental switch, for example, bundle exec jekyll serve --incremental, can speed things up a bit, but there are issues here. One is that it still builds many pages, tags, and categories as it updates, and the second is that if you’re using collections, it misses rebuilding pages that reference that collection.

Verdict: Not great.

WSL2 or a Mac?

My primary dev box these days is a beefy Windows box. Jekyll doesn’t seem to want to run under native Windows, and Windows Subsystem for Linux (WSL) can be pretty slow compared to a Mac. Microsoft announced Windows Subsystem for Linux 2 (WSL2) which will be much faster but, it isn’t available until June 2019 to insiders.

Verdict: Hold tight.


Hubber extraordinaire Ben Balter developed the Jekyll Include Cache which can help speed up building.

The approach it uses is that you can switch out a regular include x for include_cached x, providing that x doesn’t depend on any state/variables. That meant my footer, sidebar, and navbar could all easily be parsed and stored just once by changing things like: {% include footer.html %} to {% include_cached footer.html %}

There are, however, places where state is required, and this plugin can still help there. For example, my header is called using {% include head.html %} and contained code like this:

<meta name="description" content="{{ page.excerpt | markdownify | strip_html | truncatewords:40 }}" />
<title>{{ page.title }} &raquo; DamienG</title>
<meta name="twitter:url" content="{{ page.url | absolute_url }}" />

What you can do here is pass parameters to include_cached and read them the other side. Replacing the include with:

{% include_cached head.html title=page.title url='page.url | absolute_url' excerpt='page.excerpt | markdownify | strip_html | truncatewords:40' %}

And changing the include itself to:

<meta name="description" content="{{ include.excerpt }}" />
<title>{{ include.title }} &raquo; DamienG</title>
<meta name="twitter:url" content="{{ include.url }}" />

Which made the header easy to read as the title, description, and URL are used multiple times for the various types of metadata (Twitter, OpenGraph, etc.)

Verdict: Some good improvement.

No paging, tags, and collections for local dev

I never actually browse the pages, tags, or collections locally but, they’re essential for the CI and publishing. I’ve manually turned them off in the past but, it’s error-prone and a pain. But there is a way to avoid that.

Move the parts of your configuration you don’t want to be part of your local build into a new configuration file. I moved the following from my _config.yml into a new _config-publish.yml:

  enabled: true
    enabled: true
    enabled: true

  enabled: true

I also moved my Aloglia configuration block here too. Now a local build with unpublished content avoids turning up in the search index!

It’s important to remember to add --config _config.yml,_config-publish.yml to any Jekyll build steps on your CI server. For example, mine has:

 - run:
    name:    Build site
    command: bundle exec jekyll build --config _config.yml,_config-publish.yml 2>&1 | tee $JOB_RESULTS_PATH/build-results.txt


 - run:
    name:    Index with Algolia
    command: bundle exec jekyll algolia --config _config.yml,_config-publish.yml

Verdict: Awesome, drops from 30s to 17s for full build.

Turn off comments for local

I thought this would have more of an impact but, it only shaves a few seconds off the site build times.

To do this add the following first and last lines to your comments.html include (I’ll probably add this to the Jekyll Blog Comments system)

{% if site.comments.enabled %}
... (existing comments.html contents here)
{% endif %}

and remember to add this to your _config-publish.yml:

  enabled: true

Verdict: Okay, drops from 17s to 15s for full build.


With these steps, my site has gone from almost 50 seconds to about 17 for a full build without incremental. With incremental, that now means about 1-2 seconds!

I can’t wait for WSL2 to push this over the edge!


No responses yet