24.10.2018

Offline first with progressive web apps [part 1/3]

Author: Wout Schoovaerts

The internet is constantly evolving. We saw this in 2004 when ajax became really popular and made websites more dynamic. The next revolution was the mobile-first approach when we stopped thinking that the user always had a 24-inch screen but instead the website should be accessible on mobile as well. And now we see a new revolution happening called progressive web apps (PWA). And this is where our journey starts.

In this blog series, I will explain how we can make a website accessible when you have no internet connection, to make it look like a native app and even fill out forms on a website when you have no connection and after a connection is made your changes will be synced with the back-end in the background.

This first part will start off by explaining PWA in more details and how we can change our app in iterations to make it more and more a PWA. The second and last thing we will do in this part will be explaining and using service workers which are the backbone of a PWA.

WHAT ARE PROGRESSIVE WEB APPS?

Progressive web apps are websites that combine the benefits of a native app with the low friction of the web. A PWA will start as a normal website, but the more the user uses it. It behaves more and more like a traditional native app.

What advantages do we get from PWAs?

  • Always available online and offline (Caching, Background-sync, …)
  • Fast load times (Caching)
  • Push notifications
  • Homescreen shortcut (Mobile)
  • Native look (Mobile)

All these advantages will become more clear in this blog series as we will touch them all.

Who has a PWA?

For most of the advantages listed above, we have to make use of the service worker.

What does a service worker do?

A service worker is a layer between the browser tabs of your website and the server. We will use a service worker mainly to intercept, modify and cache requests. A nice thing to notice is that a service worker still lives inside your browser so it can work without an internet connection and still serve files that the service worker has cached. But maybe one of the best things about a service worker is that you control it by writing JavaScript so there is no need to learn a new language.

How does a service worker work?
The website we will transform into a progressive web app

I created a Github project where all the code for this blog series will live. To get the app we will start to transform you can check out the tag: PT1_0-the-app.

If you look at the code you can see two directories name: server and client. We will do all the coding inside the client directory.

The server

If you look at the server directory you can see that there is a real simple Express.js REST API. The REST API holds data with an array so if you restart the server you lost the data you added or updated.

To run the server you only have to execute the following commands:

cd server npm install npm start 
The client

The client is a simple web application that has a welcome screen (index.html) with a nice background image.

PWA Homescreen

The second page is where we have the real app (voter.html). We have a page with a small form to add videos. Below that we have a list of videos that you can vote up and down. All of this is controlled by a JavaScript file with ajax calls (js/voter/voter.js).

PWA Website voter

To run the server you only have to execute the following commands:

npm install http-server -g cd client http-server 

If you have done this correctly you should see the site on: http://localhost:8080

Let’s start transforming towards a progressive web app

So we have setup our normal website. We learned what a progressive web app is and we have seen what a service worker is. Let’s put this into practice and let’s use a service worker and show a custom screen when the user as no internet connection.

You can simulate an offline connection in chrome by going to your developer tools → Network → Tick the offline checkbox.

Chrome dev tools – network tab

If you have done this and you refresh the page in chrome you should see the dinosaur. And if you want you can play the fun little game.

Creating our service worker

Now we have no internet connection we want to show something more related to our website instead of that dinosaur. They are extinct anyway. To do this we can use the power of a service worker. The first step of course is to create one. Let’s do this now.

Create a new JavaScript file under the js folder with the name app.js (js/app.js). And add under the other script tags from index.html and voter.html.

In app.js add the following code:

if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/service-worker.js")         
    .then(function (registration) {
      console.log("Service Worker registered with scope:", registration.scope);
    })
    .catch(function (err) {
      console.log("Service worker registration failed:", err);     
    }); 
} 

This code does a couple of things. It starts off with checking if our browser supports service workers. After that, we register a service worker and give it the JavaScript file name where the code will live for that service worker. The register function returns a Promise and we can use the then function to say we created our service worker successfully or we can use the catch function to execute logic when the service worker failed to create.

The service workers JavaScript file should be on the root of your website for now and not under the js folder. This has to do with the serviceworkers scope. More info in this youtube video:

Create a new JavaScript file under the root folder with the name service-worker.js and add the following code to that file:

self.addEventListener("fetch", function(event) {
   console.log("Fetch request for:", event.request.url); 
}); 

This will log every fetch request your app makes to your server. So you can see that the requests pass the first trough the service worker. You can as well fetch the code with the tag: PT1_1-service-worker

Chrome dev tools – network tab

We will keep updating our service worker, but those changes will not be reflected in the browser because the old service worker is still active. This has to do with the life cycle of a service worker. For now go to developers tools → Application → Service Workers &rarr Tick the checkbox ‘Update on reload’

Chrome dev tools – service workers
Showing a custom offline page

Replace the code of our service-worker.js with the following:

var responseContent = "<html>" +     
    "<body>" +     
        "<style>" +     
            "body {text-align: center; background-color: #333; color: #eee;}" +
         "</style>" +     
         "<h1>Video Voter</h1>" +     
         "<p>There seems to be a problem with your connection.</p>" +     
     "</body>" +     
"</html>"  

self.addEventListener("fetch", function(event) {
    event.respondWith(
        fetch(event.request).catch(function() {
            return new Response(responseContent, {
                headers: {"Content-Type": "text/html"}
            });
        })     
    ); 
}); 

What this code snippet does is the following: It listens for fetch events and if it detects that fetch fails we create a new response in JavaScript with the Response object. We give it our response content which contains the html and tell it that the response has a Content Type of text/html.

If you put your browser again in offline mode you will see the following:

PWA – Website offline

The code can be found under the tag: PT1_3-offline-page

Conclusion part 1

We learned what a progressive web app is and how service workers fit into this landscape. After that, we created a service worker and gave the user a different offline experience.

In the next part, we will explain some advanced caching strategies with service workers and then implement them on our website to improve the load time.

gallery image