Karl
minimal viable service worker adactio.com/journal/13540
I really, really like service workers. They’re one of those technologies that have such clear benefits to users that it seems like a no-brainer to add a service worker to just about any website.
The thing is, every website is different. So the service worker strategy for every website needs to be different too.
Still, I was wondering if it would be possible to create a service worker script that would work for most websites. Here’s the script I came up with.
The logic works like this:
So HTML files are served network-first, while all other files are served cache-first, but in both cases a fresh copy is always put in the cache. The idea is that HTML content will always be fresh (unless there’s a problem with the network), while all other content—images, style sheets, scripts—might be slightly stale, but get refreshed with every request.
My original attempt was riddled with errors. Jake came to my rescue and we revised the script into something that actually worked. In the process, my misunderstanding of how await works led Jake to write a great blog post on await vs return vs return await.
I got there in the end and the script seems solid enough. It’s a fairly simplistic strategy that could work for quite a few sites, but it has some issues…
Service workers don’t perform any automatic cleanup of caches—that’s up to you to do (usually during the activate event). This script doesn’t do any cleanup so the cache might grow and grow and grow. For that reason, I think the script is best suited for fairly small sites.
The strategy also assumes that a file will either be fetched from the network or the cache. There’s no contingency for when both attempts fail. So there’s no fallback offline page, for example.
I decided to test it in the wild, but I expanded it slightly to fix the fallback issue. The version on the Ampersand 2018 website includes a worst-case-scenario option to show a custom offline page that has been pre-cached. (By the way, if you haven’t got a ticket for Ampersand yet, get a ticket now—it’s going to be superb day of web typography nerdery.)
Anyway, this fairly basic script seems to be delivering some good performance improvements. If you’ve got a site that you think would benefit from this network/caching strategy, and it’s served over HTTPS, then:
serviceworker.js,script element at the bottom of your HTML pages:
if (navigator.serviceWorker && !navigator.serviceWorker.controller) {
navigator.serviceWorker.register('/serviceworker.js');
}
You can also use the script as a starting point. You might find issues specific to your particular website. That’s okay—you can tweak and adjust the script to suit your needs.
If this minimal service worker script proves in any way useful to you, thank Jake.
minimal viable service worker adactio.com/journal/13540
bookmarked adactio.com/journal/13540 Minimal viable service worker! by @adactio yay!
“Adactio: Journal—Minimal viable service worker”adactio.com/journal/13540
Minimal viable service worker adactio.com/journal/13540 Good explanation and copy+paste from @adactio
Good post “Minimal viable service worker” adactio.com/journal/13540
“Minimal viable service worker” adactio.com/journal/13540/… #techblogs #feedly
A Minimum Viable Service Worker by @adactio buff.ly/2oPkHlp
Minimal viable service worker – a great script by @adactio to start using #serviceworker on your own site: adactio.com/journal/13540
In “Minimal Viable Service Worker”, @adactio writes that service workers have such clear benefits to users that all websites ought to have one, and offers a minimal script that anyone can copy and paste to add caching and offline capabilities: adactio.com/journal/13540 #webdev
Adactio: Journal—Minimal viable service worker adactio.com/journal/13540
Adactio: Journal—Minimal viable service worker adactio.com/journal/13540
In the last post about this blog I wrote about why I removed the service worker which made this blog a progressive web application.
The way my blog handles CSS predates the wide availability of service workers.
Since CSS link tags are blocking, it’s good to give CSS a long cache time. In
order to do this, but still deliver fresh CSS without readers having to wait for
it, I give the CSS file a URI including a hash of its content. If the CSS
is updated, its URI changes, as does the href of the CSS link tag in each page
of this blog.
The server sends this header along with CSS it serves:
Cache-Control: max-age=315360000, public, immutable
The immutable tells the browser the file will never change. The long max-age
is a fallback for browsers which don’t support immutable. public lets any
proxies know that they can cache it too.
I instructed the browser not to cache HTML at all. Since the HTML was always fresh, updated CSS would be loaded at most once on each change. The server sends this header along with HTML:
Cache-Control: no-cache
Which forces it to make a fresh request for HTML each time. These headers are still in place now (even since the move to Netlify).
Unfortunately this didn’t mesh well with the caching strategy of the service worker I added. The worker would download the entire blog, HTML and CSS, the first time a user navigated to it. The service worker was generated by sw-precache, which I had set up to be generated every time the blog was updated. It worked out what to add and remove from its cache based on file hashes. Since an update to CSS† meant changing the address in a link header in every HTML page, it removed not only the CSS, but all the HTML any time the CSS changed. Worse, it proactively downloaded all the updated files.
The net effect was minor CSS changes triggering a mass download of my blog. This wasn’t a good use of server or browser resources, so I removed the worker.
I recently attended a Homebrew Website Club held by Jeremy Keith. By chance he’d written a blog post on this issue the day before, in which he provides a minimum viable service worker.
This service worker caches everything lazily (no precache). When an HTML page is requested, it always tries the network first for a fresh copy, and falls back to the cache when necessary. For everything else it hits the cache first, but gets an update via the network in the background.
This resolves the CSS issue very nicely. Old CSS and HTML will be cached, so if your Southern Rail train is stuck in a tunnel, you can still read that blog entry about mixins you saw earlier and are now bored enough to take another look at. If you’re stuck outside of a tunnel and I’ve updated the CSS‡, the request for fresh HTML will succeed, which will also bring in and cache the fresh CSS! For things like images, which will probably never change, this also works well. If a change is urgent to any file, it can still be given a fresh URL to cache bust it (though I doubt this’ll ever be necessary).
I’ll still need to do some work though. As mentioned in that post, cleanup isn’t addressed. I’m happy for HTML to be cached indefinitely, but for the CSS one way to clean it up might be to remove it once it is older than every HTML entry in the cache. For particularly large resources such as images, a relatively short cache time and good alt-text might be a good approach…
In the meantime, I’ve borrowed the service worker code from that post mostly
unchanged (most changes are just to align it with the style enforced by my
ESLint config). The one small addition is to allow server sent events
(EventSource) connections. I use these in development to hot-reload my blog
when changes are made. The original script ignores all but GET requests:
if (request.method !== 'GET') { return;
}
I’ve extendded this to also ignore server sent event connections:
const acceptHeader = request.headers.get('Accept'); if (request.method !== 'GET' || acceptHeader.includes('text/event-stream')) { return;
}
You can see the current service worker code I’m using here.
† I had to add some CSS to handle superscripts, such as the one used for this footnote.
‡ Perhaps the blog will be a different shade of beige…
Minimal viable service worker: adactio.com/journal/13540 “I was wondering if it would be possible to create a service worker script that would work for most websites.”
Minimal viable service worker adactio.com/journal/13540?…
I’m in San Diego where I’ll attend the W3C WAI Education and Outreach WG Face-to-Face meeting, and CSUN, the biggest accessibility conference. It’s always amazing to be able to work with my colleagues in one room and to meet all accessibility experts in one place.
Beta: W3C/WAI Website – We managed to launch the beta for the new WAI site last week. There are still a few rough edges, but it is essential to get it in front of people. A lot of work from many people went into the site, from design, user testing, development. I made sure we can edit resources in their respective Jekyll projects on GitHub and then integrate it into one repository using git submodules. All repositories use one common theme, so changes to it will be reflected in all resource previews, hosted on GitHub pages.
Color: Colorblind Accessibility on the Web – Fail and Success Cases – An excellent overview of colorblindness and common pitfalls.
Principles: Accessibility Interview Questions – Everyone should have answers to the question collected by Scott O’Hara. Most aim at general principles than specific techniques.
Notifications: Inclusive Components: Notifications – Another excellent write-up by Heydon Pickering.
Buttons: Designing Button States – Tyler Sticka on different aspects of button design. Sweating details like this can greatly improve the usability and accessibility of your website or application.
PWA: Minimal viable service worker – I don’t know enough about Progressive Web Apps to implement them correctly, yet. However, Jeremy Keith’s article feels like a good starting point to learn more about it.
Fonts: Shipping system fonts to GitHub.com – Interesting article on a very particular approach to shipping fonts.
I’m in San Diego where I’ll attend the W3C WAI Education and Outreach WG Face-to-Face meeting, and CSUN, the biggest accessibility conference. It’s always amazing to be able to work with my colleagues in one room and to meet all accessibility experts in one place.
Beta: W3C/WAI Website – We managed to launch the beta for the new WAI site last week. There are still a few rough edges, but it is essential to get it in front of people. A lot of work from many people went into the site, from design, user testing, development. I made sure we can edit resources in their respective Jekyll projects on GitHub and then integrate it into one repository using git submodules. All repositories use one common theme, so changes to it will be reflected in all resource previews, hosted on GitHub pages.
Color: Colorblind Accessibility on the Web – Fail and Success Cases – An excellent overview of colorblindness and common pitfalls.
Principles: Accessibility Interview Questions – Everyone should have answers to the question collected by Scott O’Hara. Most aim at general principles than specific techniques.
Notifications: Inclusive Components: Notifications – Another excellent write-up by Heydon Pickering.
Buttons: Designing Button States – Tyler Sticka on different aspects of button design. Sweating details like this can greatly improve the usability and accessibility of your website or application.
PWA: Minimal viable service worker – I don’t know enough about Progressive Web Apps to implement them correctly, yet. However, Jeremy Keith’s article feels like a good starting point to learn more about it.
Fonts: Shipping system fonts to GitHub.com – Interesting article on a very particular approach to shipping fonts.
Everyone’s talking about Service Worker, but what is it? @adactio has a great write-up on what they are, but also a minimal viable service worker! dlvr.it/QMR9Mn
iOS 11.3 and macOS Safari 11.1 are out and the new versions support services workers. #MondayMotivation adactio.com/journal/13540
test webmention https://adactio.com/journal/13540
Minimal viable service worker adactio.com/journal/13540 Found with opr.as/operabrowser