Progressive Web Apps

Table of Contents

  • What is PWA and its components ?
  • Promises
  • Service Worker
  • Caching and pattern generally followed to cache 
  • Push Notifications
  • Background Sync
  • Manifest

What is PWA ?

Progressive web apps are normal websites that harness the app power to serve offline, cache data for better user experience, deserves to be on home screen for quicker accessibility, increases engagement with user through notifications, etc.

Components of  PWA ?

  • Progressive (Native look and feel)
  • Responsive (Device independent)
  • Network Independent (Offline)
  • App like (Add to home screen)
  • Re-engagable (Notification)
  • Caching 
  • Safe for content

Promises

Prior to promises, there were callbacks. If not managed properly, added quite some of the spaghetti code and usually not very good to read.

let doSomething = function() {
    if(error) return error;
    
    onceDoneDoThis() {
        ThenDoThisAfterFinish() {
            ...
        }
    }

}

Nodejs is non-blocking for I/O operations, but not good for CPU intensive work.

Promises

let loadData = function() {
    return new Promise(function(resolved, rejected) {
        request('someUrl', function(err, userInfo))
        if(err) {
            return rejected(err);
        }

        return resolved(userInfo);
    });
}

Promise

Pending

Resolved

Rejected

Promises

let fetchData = request('url'); // This returns a promise.

fetchData
    .then(addDataToUI)
    .then(addFunctionalityToUI)
    .catch(showErrorToUI)

A promise would always be settled through a resolve or a reject. So in the above example, even though "addDataToUI" fails it would continue. The value from the last promise would continue to the next then.

References

Service Worker

Since JavaScript is single threaded, any UI manipulation on the DOM would block the user interacting with the page.

 

Service worker can be compared to a browser thread which free-ups DOM interaction. Service worker cannot directly manipulate the DOM but can listen to the events and updates the events.

Things about SW

  • SW can intercepts network calls. Since it is programmable, to make it secure, it only runs on https. Exception is localhost. This is for development.
  • It is invoked / registered once the page starts to load.
  • It is terminated when not in use and starts again when required.
  • It uses promise extensively.
  • They are registered per domain and cannot access other domains.
  • The SW gets updated when updated sw is available if force updated or user navigates from page to page.

Things about SW

Example of a service worker where it executes.

Getting started...

SW

Install

Error

Activated

to be updated

Idle

Fetch/ Message 

Terminated

SW gets terminated when not in use and again spins-up when required.

Registering SW to page

// Check if service worker is supported in browser.

if('serviceWorker' in navigator) {
    navigator.serviceWorker.register('pathToServiceWorker.js')
         .then(function(sw) {
            console.log("Service Worker registered successfully", sw);
         })
         .catch(function(error) {
            console.log("Could not register SW");
         })
} else {
    console.log("Service Worker not supported in your browser");
}

Check if service worker is supported in browsers from here

Life cycle of a SW

  • Install : This would be called when we try installing the sw to the page, update a new sw.
    • Cache all the static contents. : event.waitUntil();
    • Skip waiting the new sw : self.skipWaiting();
    • Update tabs, etc. using same SW : clients.claim()
  • Activate : Tells which sw is active. You can delete all the previous cache from the browser as new cache are generated. 
  • Fetch : This intercepts the network call. The main logic is here.

Example SW

In the page, I have deleted unnecessary cache which gets accumulated. Below is the part of code which does this. 

Feel free to clone the repo and tweak.

self.addEventListener('activate', function(event) {
  console.log('SW activated ', version, ' -> ', new Date().toLocaleString());
  event.waitUntil(
    caches.keys().then(function(keys) {
      return Promise.all(
        keys.filter(function(key) {
          return key !== version;
        }).map(function(key) {
          return caches.delete(key);
      }));
    }));
});

References

Caching

Main component of PWA is app-like feel and not let the website crash without the internet. For that we need to cache contents and show them when not online.

  • Network only : Checks and serves from network only. Generally used for dynamic content like "non-get".
  • Cache only : Caches during install and serves them. Used for static contents.
  • Network first : Fetches from network and stores in cache and serves them. If network fails, serves from cache.
  • Cache first : Serves from cache, if not found, fetches from server, updates the cache to serve later.
  • Stale while revalidate : Triggers both network & cache, updates the cache when network data comes.

Some commonly used patterns are :

Caching

Code please

Cache first approach

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(res) {
      if(res) {
        return res;
      }

      if(!navigator.onLine) {
        return caches.match(new Request(offlineHtml));
      }

      return fetch(event.request);
    }));
});

checks the cache, if not found, checks whether online, if not serves offline page, else go to network.

When cache bursts ? 

There are header tags which makes sure we update stale data. Those are ETag, Last Modified Date, Cache-control, max-age, etc which makes sure we update the stale data and cache.

Any tools to make life easy ?

Data storage

Apart from file caching, we would also require data caching. If we can store data from page to page, then we can reduce calling the server for small data.

 

For this, we have localStorage, sessionStorage, indexedDB. Below is the example for indexedDB.

Push Notification

Apart from caching the content to give app like feel, we also need our users to come back to our sites to know about activity happening here. This can be done using a push notification. Below is an example of the same.

What do I need ?

A list of things needs to be known to push a notification.

  • Application Id / host id / Subscription object
  • Message what the server wants to send the user / application
  • Icons to visually suggest the user where the notification is coming from.
  • Handle block events if the user do not want to get notifications any further.

Push Api ?

The above link would show if a browser version supports push api or not. Some resources are below :

Manifesting Apps

Its always good to give information about the application if you want to make your user bookmark / place it to the home screen. Before using it, we can check if browser supports or not from the link below.

Getting started

You just have to add a link tag to your manifest file in the head of the html.

 

<link rel=“manifest” href=“/manifest.webmanifest”>

 

Mime type is optional: application/manifest+json.

A sample manifest file

{

 "name": "Music for Web Application",

 "short_name": "Music",

 "start_url": ".",

 "display": "standalone",

 "background_color": "#fff",

 "description": "Searching web for music",

 "icons": [{

   "src": "images/touch/music168.png",

   "sizes": "168x168",

   "type": "image/png"

 }, {

   "src": "images/touch/music192.png",

   "sizes": "192x192",

   "type": "image/png"

 }],

 "related_applications": [{

   "platform": "play",

   "url": "https://play.google.com/store/apps/details?id=music"

 }]

}

A working example

Feel free to clone it and play around with the colours and icons.

Progressive Web Apps

By Jagat Jeevan Sahoo

Progressive Web Apps

Things to know when you want to give app like feature to websites.

  • 480