devlog/content/posts/hard-problem.md

64 lines
3.7 KiB
Markdown
Raw Normal View History

2024-11-13 21:20:45 +00:00
+++
date = '2024-11-13T14:24:21+01:00'
draft = true
2024-11-14 21:34:09 +00:00
title = 'Hard Problem? Invalidating the browser cache'
2024-11-13 21:20:45 +00:00
+++
**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), 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.
2024-11-14 23:49:17 +00:00
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 problem handily for me, on my machine. But what about other people's machines? I need 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, and understand at a deep level.
2024-11-13 21:20:45 +00:00
## Invalidating cached HTML
2024-11-14 23:49:17 +00:00
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`.
2024-11-13 21:20:45 +00:00
```html
2024-11-14 23:49:17 +00:00
<meta http-equi"pragma" content="no-cache" />
2024-11-13 21:20:45 +00:00
```
## Invalidating cached CSS
2024-11-14 23:49:17 +00:00
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?
2024-11-13 21:20:45 +00:00
### Using a query
Of course there is. Look at this:
```html
2024-11-14 23:49:17 +00:00
<link rel="stylesheet" href="css/defaults.css?2"/>
2024-11-13 21:20:45 +00:00
```
2024-11-14 23:49:17 +00:00
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.
2024-11-13 21:20:45 +00:00
2024-11-14 23:49:17 +00:00
### Automating query insertion
2024-11-13 21:20:45 +00:00
```bash
#!/usr/bin/env bash
COMMIT="$(git rev-parse HEAD)"
2024-11-14 23:49:17 +00:00
sed -i "s/css?=\w*/css?${COMMIT}/g" index.html
2024-11-13 21:20:45 +00:00
```
Let's talk real quick about what's happening here:
2024-11-14 23:49:17 +00:00
`COMMIT="$(git rev-parse HEAD)"` gets the commit id from Git and assigns it to the variable `$COMMIT`.
2024-11-13 21:20:45 +00:00
2024-11-14 23:49:17 +00:00
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.
2024-11-13 21:20:45 +00:00
Now, whenever we push a new commit, any CSS imports in `index.html` will be changed to something like this:
```html
2024-11-14 21:34:09 +00:00
<link rel="stylesheet"
2024-11-14 23:49:17 +00:00
href="css/styles.css?ab10c24280844c10c10c1adfb8b85b03b316f72b"
2024-11-14 21:34:09 +00:00
/>
2024-11-13 21:20:45 +00:00
```
2024-11-14 23:49:17 +00:00
Now I just need to add the build script to my Jenkinsfile, and the problem is solved.
2024-11-13 21:20:45 +00:00
Pretty neat, huh?
2024-11-14 21:34:09 +00:00
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...