Fork me on GitHub

Cache Busting

Cache's are used as a way to avoid repeating work that has already been done – in this case, downloading your CSS or JS files. On the web, browsers implement client-side caching through the use of ETag and the more recent Cache-Control headers.

Most static file servers, such as Nginx, will provide ETag caching out-of-the-box, with no changes required. However, they will not automatically return Cache-Control headers, and for good reason. ETag caching requires that the client verify their cache is up-to-date before using it, via a 304 Not Modified response. This means that clients will, in theory, get the benefits of caching while always showing the most up-to-date file. On the contrary, Cache-Control headers may signal to the client to not verify the cache is up-to-date before using it, meaning that the behavior of the clients with cache-control headers may differ than from if they were not there at all.

Although such behavior from Cache-Control seems undesirable, it can significantly reduce the load on the server and increase the perceived loading speed of the site. This is because for small files, it often takes almost the same amount of time to ask the server if it's valid as it would have to download the file – defeating the point of the cache!

Fortunately, for static files, it is possible to get most of the benefits of Cache-Control while still providing the guarrantees of ETag with only a very minor overhead. HTML files can be served with ETag caching (or weak Cache-Control settings such as must-revalidate) to ensure the client has the most up-to-date version. However, all subresources are specified in the HTML file, and hence we can tell the client whether they are up to date on those without an individual request per subresource!

This is achieved by noting that browsers include the query parameters in the cache, so Vanilla Plus JS injects a query parameter everywhere you import a file which changes when that file changes. Thus even if using strong cache-control settings (even immutable), the client will still download the file if it is not up-to-date. This requires no source code changes.

However, to take advantage of this, the static file server must provide the appropriate cache-control headers. The simplest setup would simply ensure all svg, jpeg, webp, css, and js files are served with Cache-Control: public, max-age=604800, immutable. If you wanted to be a bit more careful, ensure that the files are being accessed with the query parameters v and pv (for version and processor version) in that order.