Progressive Web AppNo Comments

Build Your First PWA in 20 minutes!

Java Interview Questions
Today we’re going to build a simple web app, which is 100% PWA, in 20 minutes. But lets first understand what Progressive Web Apps are.

PWA is Google’s technology to provide features of native mobile app, to any web application. Like option to ‘Add to Home Screen’, work offline, sending ‘Push Notifications’, using mobile’s features like camera, geolocation etc.


PWA has certain requirements which have to be met:-

• Website should be served on https:, for development you can use localhost.

• Website must have install a ‘Service Worker’, a background javascript process

• Website must be able to work offline, at-least the basic shell of website

Find out which browsers and their versions support service workers.
Now lets get our hands dirty. In this example we will be creating a simple html website.

git Download the code from GitHub

This is how our PWA will look like on mobile:-

PWA-Final-App


Environment Setup :-
You need a server for this, because remember ‘localhost’ from above. You can use npm to install an http server as below. Or you can just use any other server you are comfortable with tomcat, wamp, etc.

npm install http-server -g


Folder Structure:-

PWA Folder Structure


Step 1:- The Manifest
manifest.json is required for mobile devices to load images, description, application short name, it has to be at root level.

  ...
  "start_url": "/",
  "scope": ".",
  "display": "standalone",
  "orientation": "portrait-primary",
  "background_color": "#fff",
  "theme_color": "#3f51b5",
  "description": "A simple Ironman PWA.",
  "dir": "ltr",
  "lang": "en-US"


Step 2:- The Service Worker
First we need to install the service worker, and add some basic files to cache, so that our app can run while offline.
Here we are caching the homepage(‘/’), style.css and an image. So, if the user has visited the website, these files would get stored in the cache, and would get rendered while offline. You must cache the start_url mentioned in manifest.json.

...
self.addEventListener('install', function(event) {
  //console.log('[Service Worker] Installing Service Worker ...', event);
  event.waitUntil(
    caches.open(CACHE_STATIC_NAME)
      .then(function(cache) {
        console.log('[Service Worker] Precaching App Shell');
        cache.addAll([
          '/',
          'css/style.css',
          'images/ironman.png',         
        ]);
      })
  )
});


Activating the Service Worker:-

...
self.addEventListener('activate', function(event) {
    //console.log('[Service Worker] Activating Service Worker ...', event);
    event.waitUntil(
        caches.keys()
        .then(function(keyList) {
            return Promise.all(keyList.map(function(key) {
                if (key !== CACHE_STATIC_NAME) {
                    return caches.delete(key);
                }
            }));
        })
    );
    return self.clients.claim();
});


Adding the Fetch event, to get files from cache:-
If the requested files are in cache load them from cache, else make a network request for them.

...
self.addEventListener('fetch', function(event) {
    //console.log('[Service Worker] Fetching something ....', event);
    event.respondWith(
        caches.match(event.request)
        .then(function(response) {
            if (response) {
                return response;
            } else {
                return fetch(event.request);
            }
        })
    );
});


Step 3:- Using the files
The following code is required to include files in index.html. Include app.js in every page, or you can put it in footer template.

<head>
<link rel="manifest" href="manifest.json">
</head>
...
<script src="js/app.js"></script>

app.js includes Service Worker(sw.js) and registers it.

if (!window.Promise) {
    window.Promise = Promise;
}

if ('serviceWorker' in navigator) {
    navigator.serviceWorker
        .register('sw.js')
        .then(function() {
            console.log('Service worker registered!');
        });
}

Also whenever you are making changes to files that are being cached by service worker(like style.css in this case), increase the cache name like from var CACHE_STATIC_NAME=’static-v1′; to var CACHE_STATIC_NAME=’static-v2′; Otherwise browser would always load the file in cache and not the latest version of file.


Step 4:- Running the app!
You can use npm command http-server “path to folder”, for me it was something like this

http-server "D:\Program Files\nodejs\localhost\pwa-app"


Step 5:- Check whether your app is actually PWA or not!

Go to Chrome developer tools – > Application tab, and check the Manifest

Manifest


Check out the Service Worker:-
Check ‘Update on reload’, it would help during development and while making changes in ‘sw.js’.

ServiceWorker


Check whether your files are in cache or not:-

Cache

Just to prove that cache actually works, you can stop the server to mimic ‘offline’ situation. We have cached ‘ironman.png’ so while offline this image still gets loaded, but since avengers.png is not cached, it doesn’t show up. But thats ok! We still are able to show a basic website to user while offline instead of an ugly 404 page.

Network-Tab

Website in Offline Mode :-

Network-Tab

Step 5:- Lets run the Chrome Lighthouse test for PWA, to see whether our website is 100% PWA or not
Go to Developer tools – > Audits and choose Progressive Web App and run it.

Audit

In the Audit results, our website is 92%. Why not 100%? Because we are running on localhost. If you host the same website with SSL(https://), your website would be 100% PWA!!

Also note, that on mobile, now we can get a prompt to install this app. Now that’s amazing!

Audit


But still I’m a bit skeptical. Until we actually see the banner on mobile and install the app, we shouldn’t feel that we have accomplished something.

You can use port forwarding to use ‘localhost’ from your desktop, on mobile. Follow this article.
Port Forwarding

And just to prove my point, here are some of the screenshots from mobile:-

Add to Home Screen Banner :-

A2HS1
        
A2HS2