84 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			HTML
		
	
	
	
| <!DOCTYPE html>
 | |
| <html lang="en-us" dir="ltr">
 | |
| <head><script src="/livereload.js?mindelay=10&v=2&port=1313&path=livereload" data-no-instant defer></script>
 | |
|   <meta charset="utf-8" />
 | |
| <meta name="viewport" content="width=device-width" />
 | |
| <title>
 | |
|   Hard Problem? Invalidating the browser cache | CODING WITH ANDRZEJ
 | |
| </title>
 | |
| 
 | |
| <link rel="stylesheet" href="/css/main.css" />
 | |
| <link rel="stylesheet" href="/css/syntax.css" />
 | |
|  
 | |
|       <script src="/js/main.js"></script>
 | |
| 
 | |
| 
 | |
| </head>
 | |
| <body>
 | |
|   <header>
 | |
|     <a href="http://localhost:1313"><h1>CODING WITH ANDRZEJ</h1></a>
 | |
| 
 | |
|   <nav>
 | |
|     <ul>
 | |
|     <li>
 | |
|       <a href="/">Home</a>
 | |
|     </li>
 | |
|     <li>
 | |
|       <a aria-current="true" class="ancestor" href="/posts/">Posts</a>
 | |
|     </li>
 | |
|     <li>
 | |
|       <a href="/tags/">Tags</a>
 | |
|     </li>
 | |
|     </ul>
 | |
|   </nav>
 | |
| 
 | |
| 
 | |
|   </header>
 | |
|   <main>
 | |
|     
 | |
|   <h1>Hard Problem? Invalidating the browser cache</h1>
 | |
| 
 | |
|   
 | |
|   
 | |
|   <time datetime="2024-11-13T14:24:21+01:00">November 13, 2024</time>
 | |
| 
 | |
|   <p><strong>I had a bit of an issue with my <a href="https://demos.ajstepien.xyz">website</a> recently.</strong></p>
 | |
| <p>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 <em>were</em> styled when I loaded the same page in Chrome.</p>
 | |
| <p>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 <code>CTR + SHIFT + R</code> (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.</p>
 | |
| <p>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.</p>
 | |
| <h2 id="invalidating-cached-html">Invalidating cached HTML</h2>
 | |
| <p>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.</p>
 | |
| <p>I can stop the HTML getting cached by by adding the following meta tag, in this case to <code>index.html</code>.</p>
 | |
| <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">  <span class="p"><</span><span class="nt">meta</span> <span class="na">http-equi</span><span class="err">"</span><span class="na">pragma</span><span class="err">"</span> <span class="na">content</span><span class="o">=</span><span class="s">"no-cache"</span> <span class="p">/></span>
 | |
| </span></span></code></pre></div><h2 id="invalidating-cached-css">Invalidating cached CSS</h2>
 | |
| <p>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?</p>
 | |
| <h3 id="using-a-query">Using a query</h3>
 | |
| <p>Of course there is. Look at this:</p>
 | |
| <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"css/defaults.css?2"</span><span class="p">/></span>
 | |
| </span></span></code></pre></div><p>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.</p>
 | |
| <h3 id="automating-query-insertion">Automating query insertion</h3>
 | |
| <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
 | |
| </span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nv">COMMIT</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>git rev-parse HEAD<span class="k">)</span><span class="s2">"</span>
 | |
| </span></span><span class="line"><span class="cl">sed -i <span class="s2">"s/css?=\w*/css?</span><span class="si">${</span><span class="nv">COMMIT</span><span class="si">}</span><span class="s2">/g"</span> index.html
 | |
| </span></span></code></pre></div><p>Let’s talk real quick about what’s happening here:</p>
 | |
| <p><code>COMMIT="$(git rev-parse HEAD)"</code> gets the commit id from Git and assigns it to the variable <code>$COMMIT</code>.</p>
 | |
| <p>Then, <code>sed -i "s/css?=\w*/css?${COMMIT}/g" index.html</code> does a find and replace on <code>index.html</code>. The regular expression <code>css?=\w*</code> 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 <code>-i</code> tells sed to edit the file in place. The <code>g</code> tells it to perform the operation on the whole file.</p>
 | |
| <p>Now, whenever we push a new commit, any CSS imports in <code>index.html</code> will be changed to something like this:</p>
 | |
| <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> 
 | |
| </span></span><span class="line"><span class="cl"><span class="na">href</span><span class="o">=</span><span class="s">"css/styles.css?ab10c24280844c10c10c1adfb8b85b03b316f72b"</span> 
 | |
| </span></span><span class="line"><span class="cl"><span class="p">/></span>
 | |
| </span></span></code></pre></div><p>Now I just need to add the build script to my Jenkinsfile, and the problem is solved.</p>
 | |
| <p>Pretty neat, huh?</p>
 | |
| <p>There’s just one thing bugging me: surely I do actually want the CSS to be cached <em>sometimes</em>. 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…</p>
 | |
| 
 | |
|   
 | |
| 
 | |
| 
 | |
|   </main>
 | |
|   <footer>
 | |
|     <p>Copyright 2024. All rights reserved.</p>
 | |
| 
 | |
|   </footer>
 | |
| </body>
 | |
| </html>
 |