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 every change to be reflected is not only a pain but quite 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 e.g. bundle exec jekyll serve --incremental can speed things up a bit but there are issues here. One is that it still builds a lot of 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 at all under native Windows and Windows Subsystem for Linux (WSL) can be pretty slow compared to a Mac. Microsoft have announced Windows Subsystem for Linux 2 (WSL2) which will be much faster but it isn’t available until June 2019 and even then that’s to insiders.

Verdict: Hold tight.

Caching

Hubber extrodinaire 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. For me 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 important and this plugin can still help there. For example my header was 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 actually also 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 very important 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!

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

autopages:
  enabled: true
  categories:
    enabled: true
  tags:
    enabled: true

pagination:
  enabled: true

I also moved my Aloglia configuration block here too so that local builds with content not yet published does not turn 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

and:

 - 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 another couple of 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:

comments:
  enabled: true

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

Conclusion

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

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

[)amien

No responses yet