Progressive Web Apps 101
Tags: pwa, javascript
Published: 2022-03-05 18:19:40

---
title: Progressive Web Apps 101
published: true
date: 2022-03-05 18:15:00 UTC
tags: ['pwa', 'javascript']
canonical_url: https://sevic.dev/notes/pwa-101/
---

Progressive Web Apps bring some advantages over native mobile apps

- automatic updates can be implemented
- the installed app takes less memory
- installable on phones, tablets, desktops

### Prerequisites for installation

- web app is running over an HTTPS connection
- service worker is registered
- web app manifest (`manifest.json`) is included

### Service worker

Read more about it on [Caching with service worker and Workbox](https://dev.to/zsevic/caching-with-service-worker-and-workbox-1f7i)

### Manifest

Following fields can be included

- `name` is a full name used when the app is installed
- `short_name` is a shorter version of the name that is shown when there is insufficient space to display the full name
- `background_color` is used on a splash screen
- `description` is shown on an installation pop-up
- `display` customizes which browser UI is shown when the app is launched (standalone, fullscreen, minimal-ui, browser)
- `icons` is a list of icons for the browser used in different places (home screen, app launcher, etc.)
- `scope` specifies the navigation scope of the PWA. It should start with the URL from `start_url` value. If the user navigates outside the scope, PWA won't be open from external URLs.
- `screenshots` is a list of screenshots shown on the installation pop-up
- `start_url` is a relative URL of the app which is loaded when the installed app is launched. PWA usage can be tracked by adding UTM parameters within the URL.
- `theme_color` sets the color of the toolbar, it should match the `meta` theme color specified in the document head

Description and screenshots are shown only on mobile phones.

```json
{
  "name": "App name",
  "short_name": "App short name",
  "background_color": "#ffffff",
  "description": "App description",
  "display": "standalone",
  "icons": [
    {
      "src": "icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "scope": "/app",
  "screenshots": [{
    "src": "screenshots/main.jpg",
    "sizes": "1080x2400",
    "type": "image/jpg"
  }],
  "start_url": "/app?utm_source=pwa&utm_medium=pwa&utm_campaign=pwa",
  "theme_color": "#3366cc"
}
```

Manifest file should be included via link tag

```html
<link rel="manifest" href="/manifest.json">
```

### In-app installation experience

It can be implemented on Google Chrome and Edge.

- listen for the `beforeinstallprompt` event
- save `beforeinstallprompt` event so it can be used to trigger the installation
- provide a button to start the in-app installation flow

```js
let deferredPrompt;
let installable = false;

window.addEventListener("beforeinstallprompt", (event) => {
  event.preventDefault();
  deferredPrompt = event;
  installable = true;
  document.getElementById("installable-btn").innerHTML = "Install";
});

window.addEventListener("appinstalled", () => {
  installable = false;
});

document.getElementById("installable-btn").addEventListener("click", () => {
  if (installable) {
    deferredPrompt.prompt();

    deferredPrompt.userChoice.then((choiceResult) => {
      if (choiceResult.outcome === "accepted") {
        document.getElementById("installable-btn").innerHTML = "click!";
      }
    });
  } else {
    alert("clicked!");
  }
});
```

### Notes

`chrome://webapks` page on mobile phones shows the list of installed PWAs with their details. `Last Update Check Time` is useful for checking when the manifest file was updated. The app is updated once a day if there are some manifest changes.

### Demo

The demo with the mentioned examples is available [here](https://sevic.dev/demos).