Table of Contents
Recently I have added offline support for this blog using Workbox. You can test this by going offline and then browsing my blog. This note gives a walkthrough of how I did it and summarizes my findings.
TLDR
Steps to enable offline support:
- Enable service worker
- Create sw.js with
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.3/workbox-sw.js'); workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
- Install workbox-cli with
npm install workbox-cli --global
- Follow workbox wizard
workbox wizard --injectManifest
- Inject
sw.js
with what to cacheworkbox injectManifest workbox-config.js
What is Workbox?
Workbox is a set of javascript libraries that add support for caching and offline access of web apps. Workbox provides an abstract layer for developers when working with service workers. Some of the things workbox support like precaching, runtime caching, etc will be covered below.
Does your browser support workbox and service workers? Check here
Enable service worker
Add this script to the bottom of your website:
<script>
// Check that service workers are supported
if ('serviceWorker' in navigator) {
// Use the window load event to keep the page load performant
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js');
});
}
</script>
This tells the browser to wait until the window load and then register for service worker in /sw.js
route.
Using Workbox
There are a few ways to generate service workers using Workbox. I choose to use workbox-cli as I can enable it as part of my build pipeline for my blog which is currently powered by Jekyll. If you use Node or Gulp, you can use workbox-build or if you use Webpack, there is workbox-webpack-plugin.
Install workbox-cli
Install by using npm:
npm install workbox-cli --global
Setup service worker
In sw.js
specify the following boilerplate code:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.5.3/workbox-sw.js');
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
Notice we have not specified anything yet to precache. This serves as an injection point for workbox to compute and inject all the routes to be cached.
Use workbox-cli to populate what to precache
Run workbox-cli wizard
workbox wizard --injectManifest
This command provides the option to specify what to cache by looking at all the file extensions in the website. After this is done, a new file called workbox-config.js
will be created.
workbox injectManifest workbox-config.js
This command then uses what is specified in workbox-config.js
and injects all the files to be cached into the injection point we specified above in sw.js
files.
Manually specify what to cache during runtime
There are already a few common recipes that provide examples of caching css, js, images, etc.
I use a few from those recipes for my site:
// Caching Images
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|webp|svg)$/,
new workbox.strategies.CacheFirst({
cacheName: 'images',
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
})
);
// Cache CSS and JavaScript Files
workbox.routing.registerRoute(
/\.(?:js|css)$/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'static-resources',
})
);
// Caching Content from Multiple Origins
workbox.routing.registerRoute(
/.*(?:googleapis|gstatic)\.com/,
new workbox.strategies.StaleWhileRevalidate(),
);
Add to build and automate
Since I am using CircleCI to deploy changes of my site to Github Pages, I also add the workbox + service worker script generation to the build.
Declared workbox-config.js
:
module.exports = {
"globDirectory": "_site/",
"globPatterns": [
"**/*.{html,txt,css,webp,js,json,svg,ico}"
],
"swDest": "_site/sw.js",
"swSrc": "sw.js"
};
In config.yml
file I added:
# -- more omitted --
- run: JEKYLL_ENV=production bundle exec jekyll build
- run: npm install workbox-cli
- run: npx workbox injectManifest workbox-config.js
# -- more omitted --
It is quite simple, just added two extra steps to install workbox-cli and run the same command to inject the precache routes.
Considerations
- Using the workbox-cli, we can cache everything on the site. However, this will not work if the website contains thousands of posts and images as everything will be downloaded to the browser cache.
- Using the workbox-cli, we can only set service workers to cache our website’s assets. It will not handle caching other website’s sites. This is important because we probably use things like external fonts, javascripts, css files, etc. So we need to manually add that support to our service workers.
Footnotes:
- 05-27-2022: Update to the latest workbox version