64 lines
3.7 KiB
Markdown
64 lines
3.7 KiB
Markdown
+++
|
|
date = '2024-11-13T14:24:21+01:00'
|
|
draft = true
|
|
title = 'Hard Problem? Invalidating the browser cache'
|
|
+++
|
|
|
|
**I had a bit of an issue with my [website](https://demos.ajstepien.xyz) recently.**
|
|
|
|
I pushed some changes incorporating images for the first time (I know -- very swish, very modern), and everything seemed to be working just fine, but when I loaded the production site... in Firefox, the images were not styled. Stranger still, they *were* styled when I loaded the same page in Chrome.
|
|
|
|
The experienced computer touchers amongst you will be saying "this is obviously a cache problem", and you're right, it is obviously a cache problem. Pressing `CTR + SHIFT + R` (which forces Firefox to clear the cache and do a full reload) proved this thesis, and solved the immediate problem for me, on my machine. But what about other people's machines? **I needed to cache-bust.**
|
|
|
|
Post-processors such as Tailwind use fancy 'fingerprinting' techniques for this, but I want something simpler than that for this project. Something I can code myself, without losing sight of what's happening under the hood.
|
|
|
|
## Invalidating cached HTML
|
|
|
|
The best way to deal with the caching problem is to tell the browser not to cache our HTML in the first place. Yes, this is kind of (100%) cheating, but c'mon bro, it's just one little HTML file --- browsers only cache those because most websites these days are glorified SPAs where the HTML rarely changes.
|
|
|
|
I can stop the HTML getting cached by by adding the following meta tag, in this case to `index.html`.
|
|
|
|
```html
|
|
<meta http-equi"pragma" content="no-cache" />
|
|
```
|
|
|
|
## Invalidating cached CSS
|
|
|
|
That's all well and good, but what I really need is for the browser to recognize my CSS as a new file and load it anew from the server. I could change the file name whenever I want to bust the cache, but this would get tedious very quickly. What's more, as far as Git is concerned, I'd be deleting the CSS file and writing a new one with every deployment. Surely there's a better way?
|
|
|
|
### Using a query
|
|
|
|
Of course there is. Look at this:
|
|
|
|
```html
|
|
<link rel="stylesheet" href="css/defaults.css?2"/>
|
|
```
|
|
|
|
As I'm requesting the file via http, I can append a query. Awesome. Not awesome enough though. I'm too lazy to do this every time I push a commit, and, being human, I'll probably forget at a critical moment. This can only mean one thing. It's time to bash (🤣) out a quick build script.
|
|
|
|
### Automating query insertion
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
COMMIT="$(git rev-parse HEAD)"
|
|
sed -i "s/css?=\w*/css?${COMMIT}/g" index.html
|
|
```
|
|
|
|
Let's talk real quick about what's happening here:
|
|
|
|
`COMMIT="$(git rev-parse HEAD)"` gets the commit id from Git and assigns it to the variable `$COMMIT`.
|
|
|
|
Then, `sed -i "s/css?=\w*/css?${COMMIT}/g" index.html` does a find and replace on `index.html`. The regular expression `css?=\w*` matches 'css?=' plus any number of contiguous alphanumeric characters (everything until the next quote mark, basically) before replacing these alphanumeric characters with the commit id. The flag `-i` tells sed to edit the file in place. The `g` tells it to perform the operation on the whole file.
|
|
|
|
Now, whenever we push a new commit, any CSS imports in `index.html` will be changed to something like this:
|
|
|
|
```html
|
|
<link rel="stylesheet"
|
|
href="css/styles.css?ab10c24280844c10c10c1adfb8b85b03b316f72b"
|
|
/>
|
|
```
|
|
Now I just need to add the build script to my Jenkinsfile, and the problem is solved.
|
|
|
|
Pretty neat, huh?
|
|
|
|
There's just one thing bugging me: surely I do actually want the CSS to be cached *sometimes*. Caching exists for a reason, and I don't want to sacrifice performance. Maybe I can modify the build script so that it only updates the CSS imports when the CSS files have changed... Sounds like a topic for another blogpost...
|