📃 Introduction to PWA set up

Practical guide to make it work for your first website

Joseph Ismail
Apr 29 · 7 min read

I will give here a brief explanation on how to optimise (well, at least the way I made it work for my first website) your PWA score from the Google Lighthouse audit.

When I ran my first Lighthouse audit, I noticed multiple warnings concerning the PWA set up. I managed to solve most of them (like the requirement for https instead of http, some required meta tag attribute, …) but I ended up struggling with the concepts of manifest.json and service worker as it was the first time I heard those words. If it is the same for you, then this article might help.

Here’s what Google’s official introduction says:

Progressive Web Apps are user experiences that have the reach of the web, and are:

* Reliable — Load instantly and never show the downasaur, even in uncertain network conditions.
* Fast — Respond quickly to user interactions with silky smooth animations and no janky scrolling.
* Engaging — Feel like a natural app on the device, with an immersive user experience.
This new level of quality allows Progressive Web Apps to earn a place on the user’s home screen.

In other words, the PWA allows you to make your website behave just like an application on smartphones, even after you loose internet connection.

As I said, the challenge for me was to set up something called the manifest.json and service worker.

  • The manifest.json is a file that will handle your favicons i.e. it will handle the images (icons, logo, …) you want to use as icons of the user application, across the various operating systems (Android, iPhone, windows 8 and 10).
  • Service workers allow the user to access your website after internet connection is lost! Basically, you define the files (e.g. a specific script.js, or a dedicated index.html) to save up in the cache of the user browser and which will be used if the user looses internet. Note the after here, as the user has to access the website at least once with internet connection in order to save up the defined files in the cache of the browser.

Here is my github repository of my first website set up for PWA so that you can follow this tutorial alongside with the code and files that made it work.

So let’s begin!

Set up the manifest.json

You can directly generate your favicons and the required files (which will constitute the manifest.json) thanks to dedicated website. Here are the two ones I worked with:

You can thus upload the pictures you want to use as the app favicons (like your logo), and these sites will generate the followings files:

  • A folder containing your uploaded image in multiple formats (for apple, android, windows 8 & 10) and in multiple sizes,
  • a file manifest.json,
  • a file browserconfig.xml (from my understanding, this file is required for windows 8 and 10 devices),
  • and a code to incorporate into your HTML <head>…</head> in order to reference all these files.


These generators do not guess where you will save these generated files and folder and thus assume the source (for generating the path) is the root of your website! If you save the files in the root, then you’re good to go. If not (this is particularly relevant in case you publish you site with a github page), consider this:

Be sure to correctly reference your files !

Example (based on my PWA website):

  • My index.html is in my main folder named “ bootstrap-resto-website” (i.e. my repository)
  • Once the files were generated by the generator, I saved them in a favicons folder, which was saved in the assets folder.
  • Nevertheless, the generator proposes me to copy the following code (I show you here a sample) in the <head>…</head> of my index.html as it supposes you saved everything in the root. Please note the href value:
<link rel=”apple-touch-icon” sizes=”57x57" href=”apple-icon-57x57.png”>
  • If you haven’t saved the generated files in your root (like me), be sure to specify the correct path for your files. As a result, my code becomes:
<link rel=”apple-touch-icon” sizes=”57x57" href=”assets/favicons/apple-icon-57x57.png”>
  1. You have now to correct the path in all code lines generated by the generator
  2. Open the manifest.json file and make sure to correct the path specified in this file as well. Here please note the the double slash \/ and begin your path with your main file (in my case, “ bootstrap-resto-website”). So that you have something like this:
“src”: “\/bootstrap-resto-website\/assets\/favicons\/android-icon-36x36.png”

3. You have to specify the path to access the browserconfig.xml. By default, the browser considers this file is for sure saved in your root and as a result, the generator does not generate the code line to access it. You have then to add it manually (I personally write it right after the declaration of the manifest.json… check out my code):

<meta name=”msapplication-config” content=”assets/favicons/browserconfig.xml”/>

So that should be it for the manifest.json story! You will probably have some other error messages from the Lighthouse audit or from the analysis of the favicons generator, but you should be able to overcome them (if not, hopefully I am not dead yet to help you out).

Set up the Service Worker

In order to understand (more or less) this concept, I kind of read that article.

Note that some open source solutions exist which set up the service worker for you (for example, upup). Nevertheless, I did not manage to make it work properly 😞. If you manage to use these solutions, good for you! If not, you can try to set it up manually, just like I did.

You can then focus on the Star Wars demo from the article. It helped me quite much to set up my service worker (and it gives some interesting tips on how to test the service worker directly from the browser console, which I will not cover here).

So let’s begin. To make it simple, there are three steps to set it up:

1. Create a file “sw.js”, where you can copy the following code

this.addEventListener(‘install’, function(event) {  event.waitUntil(    caches.open(‘v1’).then(function(cache) {      return cache.addAll([        ‘/bootstrap-resto-website/’,        ‘/bootstrap-resto-website/offline/acceuil_offline.html’,        ‘/bootstrap-resto-website/index.html’,        ‘/bootstrap-resto-website/carte.html’,        ‘/bootstrap-resto-website/gallerie.html’,        ‘/bootstrap-resto-website/restaurants.html’,        ‘/bootstrap-resto-website/contact.html’,        ‘/bootstrap-resto-website/assets/img/failed_download.png’,
this.addEventListener(‘fetch’, function(event) {


// caches.match() always resolves
// but in case of success response will have value
if (response !== undefined) { return response; } else { return fetch(event.request).then(function (response) {
// response may be used only once
// we need to save clone to put one copy in cache
// and serve second one
let responseClone = response.clone(); caches.open(‘v1’).then(function (cache) { cache.put(event.request, responseClone); }); return response; }).catch(function () { return caches.match(‘/bootstrap-resto-website/assets/img/failed_download.png’);
  • The first bold part includes the files that the service worker will save in the cache of the users browser. It should basically include your index.html, your additional pages, your images, your style.css, …
  • The second bold part (at the bottom of the code) can be considered your default element to display in case a file is missing in the cache. For example, I included the file gallerie.html to be saved in the cache. This page is supposed to display some pictures. But in case the pictures were not saved in the cache before internet connection is lost, the browser will not find the pictures to display and will, by default, display failed_download.png. Note that I specified this file twice: first in the part to specify the files to save in the cache, and second in the part to specify which file to use by default.
  • You can now include the files that you want to save in the cache of the user browser and that will be used after internet connection is lost. The browsers consider that the path of the files begins at the root, so if you are hosting your site with a github page like me, make sure to begin your url with you main folder name i.e. your repository name.

2. At the beginning of your “script.js”, you should add the following code

// register service worker — BEGINNINGif (‘serviceWorker’ in navigator) {  navigator.serviceWorker.register(‘/bootstrap-resto-website/sw.js’, {scope: ‘/bootstrap-resto-website/’}).then(function(reg) {    if(reg.installing) {      console.log(‘Service worker installing’);    } else if(reg.waiting) {      console.log(‘Service worker installed’);    } else if(reg.active) {      console.log(‘Service worker active’);
}).catch(function(error) {
// registration failed
console.log(‘Registration failed with ‘ + error);
// register service worker — END
  • This part of code will check if the user browser supports a service worker and act accordingly.
  • Make sure again to specify the path to your files considering you are in the root.

3. As you should be used to, call your “script.js” from your “index.html”

<script src=”assets/js/script.js”></script>

This way, your index.html will call your script.js, which will (in case the user browser supports the service worker) call your sw.js, which will save all the specified files in the cache.

And here it is! Your service worker should be set up 😎


  • I made it brief here, so you will surely have to haggle !
  • You will encounter quite a few problems 😑 (tip: if nothing works as expected, try to delete all the cache and service workers of your browser and try again).
  • But you will overcome them ! 😁✌
  • Once it is all done, you can try by opening the website on a smartphone (better to use a last generation device), and select the option to “add it to your homescreen.” You should see it appears, opens and acts just like an app! 👏
  • I hope I can still be available to help you out, in addition to many tutorials you can probably find on the holy web.
  • This was my first experience with PWA setup (and my first Medium article), I cannot claim it was perfectly set up. If you have comments, critics, advises,… do not hesitate to reach out 🐱‍🏍

Useful Links


BeCode: Learn to code, get a job !

Thanks to Ma·e

Joseph Ismail

Written by

Born human



BeCode: Learn to code, get a job !

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade