If you are visiting this website from a mobile device, you might have seen the following message at the bottom of the screen. No, I am not trying to hack you. I have made my website a progressive web app and, as such, it can be accessed offline and it can be installed in Android and iOS devices. Keep reading and turn your website into a PWA in less than 15 minutes!

Add PWA to home screen prompt

Add PWA to home screen prompt

The magic behind the progressive web apps are the service workers. To cut a long story short, a service worker is a script that the browser runs in the background, in a separate thread from the UI, providing additional features such as the ability to intercept and handle network requests as well as managing a cache of responses. In fact, this is the only feature we will need to make our website available offline.

A service worker lifecycle is completely separate from the web application so, first, it must be registered through the browser navigator API. You will want to register the service worker as soon as possible so all the application requests are intercepted and handled (including the application Javascript files themselves). For that reason, I place the service worker registration in a script tag inside the head tag of the HTML page:

The register method tells the browser to search for a service worker in the sw.js file and will start the install step in the background. Thus the next thing to be done is to tell the service worker what to do during the install step which, typically, will consist in caching some static assets.

There are multiple caching strategies to choose from when it comes to service workers and they are all very well explained in the offline cookbook. Take a look at them to know which patterns there are and which ones suit better your application needs (you might apply different strategies depending on the type of resource being cached and how often they get updated). I chose the network falling back to cache strategy for my webpage for the following reasons:

  • Simplicity. There are better performing strategies (e.g. Cache then network or Cache & network race) but they add more complexity to the service worker implementation. Let's keep in mind that the only goal of this exercise is to make the website available offline, not to optimize the time to content
  • I first started with cache falling back to network for better performance but, given I frequently update the application, I was getting errors due to old versions of static assets being cached. Feel free to dedicate some time to solve those errors but, again, the purpose of this tutorial is just to make the website available offline

So, without further ado, let's implement the service worker. First we need to add a specific set of files to the cache during installation. If all the files are cached successfully, then the service worker becomes installed and we get those static assets available in the cache. If any of the files fail to download and cache, then the install step will fail and the service worker won't activate (not the end of the world though, it will try to install again the next time the page is loaded).

The shorter the list is the least chances the installation has to fail (and the rest of assets can be cached later on anyway). In my case, I am only caching the landing page of my site. The self property is a reference to the WorkerGlobalScope (available only in service worker threads):

Now let's get the work done! The most important part of our service worker is the fetch listener. This handler will intercept every network request and will allow us to serve a cached version of a given resource, which, due to the Network falling back to cache strategy, will happen only if the corresponding network request fails (lines 35-37). Don't forget to add the asset to the cache on a successful network response in order to keep the cache content updated (line 31). The clone method is required because the responses can only be consumed once.

Optionally, an activate listener can also be defined in order to run some tasks each time the service worker is successfully installed. This feature comes handy to clear the application cache every time the service worker is updated. You don't need to do this but remember the universe tends to disorder and is our duty to keep the application clean and tidy; remove the files you are no longer going to need and make the users happier by freeing space up in their devices.

Once the server worker is put into place the browser will start caching every network request. You can have a look at the contents of your application cache in the Application tab of the Chrome Developer Tools. Once all the content you need has been cached, you can also test the application offline behavior by checking the Offline box and refreshing the page. Notice how the network requests fail and the assets are served from the service worker:

Service worker cache files

Service worker cache files

Files being served from service worker cache

Files being served from service worker cache

Congratulations 🎉 Your application just turned offline friendly! You are free to go playing now... but I still have something cool to show you. See that manifest.json file inside the head tag of the HTML page? It has certainly nothing to do with the service worker. That file is what will make your application ready to be installed in mobile devices for free and it only takes a few minutes to add it. It's content is self-explanatory and here are some screenshots of how professional your web will look like when installed in a mobile device:

PWA install notification
PWA starting
Offline PWA in mobile device

That's the end of it! As promised, you can turn your website into an offline available progressive web app in less than 15 minutes. Reach me at capellas.carles@gmail.com if I haven't been clear enough about any aspect and see you in the next post!

Posts timeline