I learnt a very important thing today in Gutenberg that affects how blocks are cached in the browser.

TL/DR – Fix block cache

When developing Gutenberg blocks you can decide whether the css is loaded globally via wp_enqueue_scripts or per block.

With wp_enqueue_scripts, when you enqueue a css or javascript file, you can supply a version number to the end of the filename so that a browser can cache the resource. This is useful as, if the filename doesn’t change, the resource doesn’t have to download it again. This means you could bump the version number of the filename, and be certain your browser would download the new one. This is the general order:

Filename: example.css?version=123
Browser: Has cached example.css?version=123 – no need to download it.
Filename updated: example.css?version=124
Browser: Cannot find local file, downloads a new example.css?version=124

Here is how you might do that, using the version number from style.css:

// Get the theme data.
$the_theme     = wp_get_theme();
$theme_version = $the_theme->get( 'Version' );

$css_version = $theme_version . '.' . filemtime( get_template_directory() . '/assets/dist/css/theme.min.css' );

// Enqueue the version number based off the theme version
wp_enqueue_style( 'webassembler-styles', get_template_directory_uri() . '/assets/dist/css/theme.min.css', array(), $css_version );

In the code above, the $css_version variable is made up of the style.css version number and the timestamp when the file was changed.

The problem

I had made a custom block for a client website a few weeks back and needed to add some new css for a layout change. Once I deployed the work (with DeployHQ) I saw that the new template was still showing my old styling, instead of the new css I’d worked on.

It was only when I pressed CMD+SHIFT+R (to do a hard refresh) that my browser cache was cleared and I saw the latest CSS files get loaded in for the block.

In theory I could tell my client to clear their browser cache but what about the hundreds of other visitors and users of the website? – I wasn’t comfortable knowing it would look broken to everyone else.

So, I opened the website in Firefox and tested the page and it was broken as I hoped. This allowed me to have an affected page for which to test on – simulating what an existing user or visitor would see. As long as I didn’t do a hard refresh, I could just keep refreshing to see if I’d fixed the issue.

What about caching?

My first thought was it could be related to website caching, set via the caching plugin. As the site is hosted in WP Engine, I used the Clear page cache button. This did nothing. I then made sure to bump the css version of style.css in the code above incase it was a global enqueue caching issue.

However, for a few months now, I’ve been using a special filter in Gutenberg to load CSS and JS code PER BLOCK, instead of via a global enqueued css file. The reason for this is for performance- if I load CSS and JS per block, only code for that block is loaded. For example, on a privacy policy page, you can just use the paragraph, link and heading blocks styling which is already built in.

This is the filter:

// Filters whether block styles should be loaded separately.
add_filter( 'should_load_separate_core_block_assets', '__return_true' );

When returning true, the above filter loads core block assets only when a block is rendered. This meant that the browser was caching the block css but I didn’t know how to

The solution

Because I load the css per block instead of the enqueue script method, I needed a way to find how to clear the block cache. I googled about block caching and came across this article:

https://support.advancedcustomfields.com/forums/topic/block-css-versioning-for-cache/

Image of forum post on ACF

Response from John Huebner:

If you are using block metadata as described here then you will need to alter the url string the version

John Huebner, ACF Forum

This eventually pointed to the Block editor reference guide talking about the Version number.

{ “version”: “1.0.3” }:
The current version number of the block, such as 1.0 or 1.0.3.

It’s similar to how plugins are versioned. This field might be used with block assets to control cache invalidation, and when the block author omits it, then the installed version of WordPress is used instead.

Block reference guide

So, it turns out that the Version number in block.json is very important. It controls the cache functionality. When this number is not set in block.json, the WordPress version is used meaning it would eventually update when WordPress is updated.

I then went back into every block.json file and added the version number. I decided to set this to a number per block, e.g. "2.0.0" rather than syncing it with the version in style.css. This gives me a more granular control over block asset loading in the future.

Back to blog