PWA ( Progressive Web App ) made simple.

Want to see how your website plays out as a mobile app? No, I am not talking about react-native or flutter. Introducing PWA(progressive web app), a concept for converting your web application to a mobile app ( sort of ).

PWA uses two files for achieving this.

  • Service worker
  • Manifest.json

Service worker: In simple words, service works will cache a page or response from the API and will serve when the site goes offline. They also listen for real-time notifications ( but we are not going to discuss those features here ).

Note: service workers will only work on localhost or HTTPS sites. 

Manifest.json: This JSON file contains the configuration that a browser uses to convert it to a PWA.

Let’s get into coding.

We are creating a simple stopwatch web app and converting it to PWA.


This is the only HTML file in our project containing the code to display our stopwatch.

Progressive Web App - index.html


Header section: 

  • Here we see a lot of meta tags and Bulma CDN included ( for styling our app ).
  • In addition to that, we have included manifest.json with the attribute ‘rel=manifest’, this line is to notify the browser that the app contains configuration for a PWA.

Body part:

  • Here we have three ids ( hours, minutes, seconds ) to display the corresponding values.
  • We have two buttons ( one for starting/pausing the stopwatch and another for clearing it ).
  • Next, we include the index.js file which contains code for our stopwatch.


Progressive Web App - index.js


  • This code checks if the browser is compatible with service workers or not ( Don’t expect service workers to run on IE ).
  • navigator.serviceWorker.register(‘/sw.js’) this line registers our service worker file ( In our case it’s sw.js – we will explore it next ). This should be done after the page is loaded.
  • Resolving the above code will tell you whether you have registered the service worker or not.
  • There might be cases where your service worker won’t register, one of the main reasons is that the service worker may contain errors (user errors ). Others do exist but there are no particular tools to detect them, instead, they recommend running a debugger to find where the execution went wrong. ( refer :
Progressive Web App - index.js


  • here we have four functions, we will look at them one by one.
  • update(id, clear) function is for incrementing time and also for clearing it, clearing a value is done by checking the parameter clear.
  • The initialise() function will initialize all the values ( hours, minutes, and seconds ) to 0. In turn, we use the update function to do that.
  • getValue(id) as the name implies is to get a particular value.
  • toggleCounter() will start and pause our stopwatch. We use the pause variable to know where we stand on toggling. ( we also change the button name, for the user to know ).
Progressive Web App - index.js


The way the setInterval works here is that it will start when the page loads and never stops, we are just using the pause to determine whether to run the code inside it or not.

If you have a better solution for stopping and resuming a setInterval kindly let me know in the comments.

  • Inside the serInterval the logic is simple when minutes reach 60, both seconds and minutes are set to 0, and the hour is incremented.
  • If seconds is 60 then minutes is incremented and seconds is set to 0.
  • And for every second ‘seconds’ variable is incremented.
  • clearCounter() will clear all the values and resets them to the initial value ( wiz. 0 ).


This file contains our service worker codes.

Progressive Web App - sw.js



  • Here self represents the ‘this’ keyword in js.
  • self.addEventListener will add event listeners globally. self.addEventListener(‘install’) is triggered when the service worker is installed in our browser.
  • event.waitUntil waits until the below event to finishes.
  • Inside this,‘simple_cache’) will create a cache with the name ‘simple_cache’, inside the callback we return all the pages that we want to cache using caches.addAll() function, here its index.html and / ( when we host on a server ).
  • This will run initially when the page is opened on any device.


We have cached our page, now we have to retrieve it right? For that, we use fetch event

  • self.addEventListener(‘fetch’), which is triggered when the app is offline and the page is refreshed.
  • Inside that we use caches.match() function to match the incoming request with our cache list, if a match is found it returns the cached data.
  • Here you can notice we use the fetch function to retrieve the cached data ( HTML page or API response ).


This file tells the browser how should we see the PWA, it includes configuration for icons, display ( full screen, in a browser, standalone ), app name, theme color …etc.

Progressive Web App - manifest.json


And that’s it with coding, let’s see the output. You have to serve the HTML file from a server ( apache or Nodejs ). But, I am using netlify to deploy our app ( refer to this link: for deploying, it’s dead easy ).

After deploying open the site in a browser, inspect the page, and navigate to the application tab.

Progressive Web App - browser application tab

browser application tab

 On the left menu select service workers, after that on the right side, you can see details about the service workers deployed on your page, in our case it’s sw.js.

Converting to PWA:

Now to convert this into a mobile app, pick up your phone and navigate to your website( in this case you have to use netlify to deploy your app because you have to serve your site using HTTPS for this to work ). Click the three dots on the top right corner ( Chrome ) and select the option ‘Add to Home screen’ and give a name to your app and click Add.

On your mobile’s home screen you will find your app with a google chrome icon with it, now if you click it, instead of going to the browser, your web app will open on a stand-alone screen.

Progressive Web App - output

That’s it, have fun coding!!!

Github link:

Leave a Reply

Your email address will not be published. Required fields are marked *

Pin It on Pinterest

Translate »