diff --git a/content/posts/hard-problem.md b/content/posts/hard-problem.md index d632db2..13d1425 100644 --- a/content/posts/hard-problem.md +++ b/content/posts/hard-problem.md @@ -8,49 +8,55 @@ title = 'Hard Problem? Invalidating the browser cache' 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. -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? +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. ## Invalidating cached HTML -The best way to deal with this problem is to tell the browser not to cache our HTML in the first place. We can achieve this by adding the following meta tag to `index.html`, and any other HTML files we don't want cached. +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 - + ``` ## Invalidating cached CSS -What we need is for the browser to recognize our CSS as a new file and load it anew from the server. We could change the file name whenever we want to bust the cache, but this would get tedious very quickly. What's more, as far as Git is concerned, we'd be deleting the CSS file and writing a new one with every deployment. Surely there's a better way? +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 - + ``` -As we're requesting the file via http, we 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! +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?v=${COMMIT}/g" index.html +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 the variable `$COMMIT`. +`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?v=${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. +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 ``` +Now I just need to add the build script to my Jenkinsfile, and the problem is solved. Pretty neat, huh? diff --git a/public/css/main.css b/public/css/main.css index 9c804e3..27037cd 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -55,17 +55,31 @@ } } +html { + width: 100vw; +} + body { background-color: var(--rp-base); color: var(--rp-text); font-family: sans-serif; line-height: 1.5; margin: 1rem; - max-width: 768px; + width: 100%; + display: flex; + flex-direction: column; + justify-items: center; +} + +main { + margin: auto; + max-width: 780px; + width: fit; + padding: 0 1em 0 1em; } strong { - color: var(--rp-rose); + color: var(--rp-iris); } em { @@ -102,6 +116,10 @@ h1 { text-shadow: 1px 1px 2px black; } +time { + color: var(--rp-gold); +} + code { background: var(--rp-surface); @@ -109,6 +127,7 @@ code { padding: 0.3em; border-radius: 1em; font-size: 1.2em; + font-style: oblique; span { background: var(--rp-surface); diff --git a/public/posts/hard-problem/index.html b/public/posts/hard-problem/index.html index 743b69d..c943696 100644 --- a/public/posts/hard-problem/index.html +++ b/public/posts/hard-problem/index.html @@ -44,27 +44,31 @@

I had a bit of an issue with my website 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.

-

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?

+

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.

Invalidating cached HTML

-

The best way to deal with this problem is to tell the browser not to cache our HTML in the first place. We can achieve this by adding the following meta tag to index.html, and any other HTML files we don’t want cached.

-
  <meta http-equiv="pragma" content="no-cache" />
+

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.

+
  <meta http-equi"pragma" content="no-cache" />
 

Invalidating cached CSS

-

What we need is for the browser to recognize our CSS as a new file and load it anew from the server. We could change the file name whenever we want to bust the cache, but this would get tedious very quickly. What’s more, as far as Git is concerned, we’d be deleting the CSS file and writing a new one with every deployment. Surely there’s a better way?

+

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:

-
<link rel="stylesheet" href="css/defaults.css?v=2"/>
-

As we’re requesting the file via http, we 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!

+
<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

#!/usr/bin/env bash
 COMMIT="$(git rev-parse HEAD)"
-sed -i "s/css?=\w*/css?v=${COMMIT}/g" index.html
+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 the variable $COMMIT.

-

Then, sed -i "s/css?=\w*/css?v=${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.

+

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:

<link rel="stylesheet" 
-href="css/styles.css?v=ab10c24280844c10c10c1adfb8b85b03b316f72b" 
+href="css/styles.css?ab10c24280844c10c10c1adfb8b85b03b316f72b" 
 />
-

Pretty neat, huh?

+

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…