Implementing a Service Worker is something I’ve only really toyed with in the past. I recently felt like I needed to get reacquainted with their inner workings again, so I decided to implement one for this blog. Here are some tips and tricks I learned along the way.
Choose a caching strategy
Caching is one of the hardest problems in programming, and also one of the main reasons why service workers can be a bit difficult to understand at first. Choosing the wrong caching strategy for your service worker can lead to unexpected and sometimes difficult to reproduce bugs, so it’s important to spend some time thinking about what will work best for your website.
The last service worker I wrote used an offline first approach. This worked out OK since it was only a single HTML page with a limited number of static assets. The service worker looked in the cache first for any
GET request, and only went out to the network if there was no match:
For this blog that’s not really what I wanted though, since when people visit I want to be sure they always see the most recent content straight away. For this reason I went for a network first approach for HTML pages, and falling back to a simple offline page if a request fails:
I could have additionally chosen to cache pages that users have already visited, and served those up if the network fails and there is a match in the service worker cache. I’m not convinced however, that my personal blog posts are really interesting enough that people actually want them heavily cached on their hard drives, so for now a simple offline page will suffice ;)
Dealing with static assets
There is a potential issue here however. What if a visitor requests an HTML page, but that page uses updated assets that no longer match what’s stored in the current service worker cache? This could lead to both visual bugs and broken behavior, which is not good. Rather than try to fight against the cache, using immutable assets is a good strategy here.
Immutability to the rescue!
Jekyll doesn’t support immutable assets out-of-the-box, but luckily there is already a plugin called jekyll-assets that can hash asset filenames for you (and more). Once I had this installed, I updated both my liquid templates and my service worker’s
updateStaticCache function to use the hashed filenames. This ensures that my service worker never accidentally responds with an outdated asset that a web page might be using, since the actual file names are individually hashed:
If you’re curious to see everything together, you can view my full service worker code here.