Cache, m*****f****r, did you clear it?

So you’re finally publishing your web app. But as you iterate upon it you notice that you’re often getting outdated versions of its resources. And that’s when it is time to think about cache-busting and cache optimizations. Let’s look at cache-busting first, we have a few options to pick from.

Querystring

First option is to use a querystring. By appending a querystring with with some sort of unique identifier to the resources we can force cache invalidation for various scenarios, like client cache, caching server cache, etc. You can use, version, file hash, timestamp or some other data that can be used for resource versioning.

Like so:
https://my.server/static/app.js?5c7e5e8420e9cd57133df701

So when you change app.js and generate a new identifier user’s browsers and other caches won’t hit the old app.js with its 5c7e5e8420e9cd57133df701 version identifier.

Next iteration of app.js:
https://my.server/static/app.js?5c7e5f5f20e9cd57133df702

Resource name

Another option is to incorporate the aforementioned identifiers into resource names. It will also cause various caches to be invalidated when you change your app. It has the downside of having to spread your resource versioning into file names. But it also has an upside of being independent from caching algorithms quirks like ignoring querystring in requests and thus always missing the cache and going to the origin every time.

Thus, previous examples would look like so: https://my.server/static/app.5c7e5e8420e9cd57133df701.js https://my.server/static/app.5c7e5f5f20e9cd57133df702.js

Optimizing resource caching

In our day and age it’s common for web apps to be quite bulky. So we can take steps to reduce the numbers of resource requests by splitting its code in several parts and invalidating only the parts that were changed during the last iteration. Good place to start would be splitting your app’s code from its dependencies. Then version those parts separately.

Instead of having one bulky app.js we could split it into main.js with our app’s code and vendor.js with all the dependencies. Now, when we make changes to our app, clients will only request the much lighter main.js which oftentimes will be multiple times smaller than the vendor.js.


Rustam Gafurov

Full-stack Developer, Python expert

bitsouls Linkedin