Progressive Web Apps


What is PWA?

There is a lot of documentation and materials about PWA, what PWA is, and how it works,… I personally recommend this one. If I tried to define PWA, I would say:

  • Offline: With integrated Service Worker to support “offline mode”
  • Installable on mobile: “look and feel” of native mobile application

and ideally, implement some of the “non-standard” browser APIs (see below) and have a responsive design.

But what will I get with PWA?

Well, let’s look at some of the screenshots. This is a PWA application open in the browser. As you can see, nothing special — a responsive application.

Responsive application

But PWA can be installed, and then when we open the application, we see:

  • Application is listed in the list of installed applications
  • After the opening of the application, we do not see “browser stuff” (like tabs, history, …)
  • It works offline!
“pwa-demo-1″ is installed application, like Chrome or Outlook

Mobile

On mobile, when you open PWA, it is just a responsive web application. But PWA can also be installed on mobile!

As on the desktop, it does share some benefits (listed as a native application, no browser stuff — much more space for the application, offline mode, …).

Create a simple PWA TODO application with Angular

First of all, PWA applications are not specific for Angular applications — React, Vue, or even “plain HTML and Javascript” web applications can use the benefits of PWA / could be installed as PWA. Everything that needs to be done is:

  • Install Service Worker
  • Publish configuration called ‘manifest.webmanifest’

Install service worker in Angular

Just run the command (angular schematics, run with Angular CLI, see doc) and see what has been added/changed:

ng add @angular/pwa
  • A new configuration, “ngsw-config.json” has been added. It is the configuration of a Service Worker. In this file, we can configure caching, preload strategy, …
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}
  • A new configuration, “src/manifest.webmanifest” has been added. Here we list application icons — images (for applications, by size), the name of the application (in the list of applications), splash screen color (during startup), … PWA “stuff” that makes our application “native-app like”.
{
"name": "pwa-demo-1",
"short_name": "pwa-demo-1",
"theme_color": "#1976d2",
"background_color": "#fafafa",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
}
...
]
}

At the end of this article, you find a link to a repository with a simple Angular PWA application.

Service worker and Offline mode

Service workers add the possibility to open and use our web application offline / without access to the internet.

  • Service worker caches all files (JS, CSS, images, …) downloaded when the web app has been open
  • In addition, it starts downloading (in the background) all files configured in the “pre-load” section of “ngsw-config.json”

When a web application is open (as a native application from the list of applications or visiting URL of a web application) -> Service Worker provides a cached version of files (therefore reducing loading time to a minimum).

Offline mode is perfect for static pages (homepage, FAQ, about section, …). With little bit of “logic” we can also allow user to order “pre-loaded” products and when user connect to internet, we can finish order (or let user know of problem).

Is PWA just about installation as a native APP and offline mode?

No! Browsers already have many built-in APIs (I called them “non-standard” because it is still not common to see them implemented), which in connection with PWA, can bring very interesting features to users — “next level of UX”. In this article, we will focus on Custom App installation and Badges.

Customize App install

Installation of PWA is simple — you click on the icon next to input, where we type a web address. Or, if we are lucky, the browser will send us a notification/message that this web is installable.

Hmm, would it not be better if we could in our application prompt the user to install it with UI, which will be impossible to miss?

Luckily, we have listeners that can:

  • Detect that app can be installed (device/browser & app support it) and prevent default browser behavior
  • Show our nice UI notification (mentioned “impossible to miss” prompt)
  • After clicking (user decides to install) — install the application

At the start, we need to detect that PWA could be installed:

  ngOnInit(): void {
// with 'beforeinstallprompt' listener we will:
window.addEventListener('beforeinstallprompt', (e: any) => {
// 1) perfect, device & browser support PWA and is not already installed!
// 2) prefent default browser install notification / message
e.preventDefault();
console.debug(`'beforeinstallprompt' event was fired.`);
// 3) we store event, store event will be used latter user for installation
this.deferredPrompt = e;
});

window.addEventListener('appinstalled', () => {
// ... app is already installed,
this.deferredPrompt = null;
console.debug('PWA was installed');
});
}

Now we know when can be PWA installed, let`s update our design:

<div class="d-flex alert alert-primary" role="alert" *ngIf="deferredPrompt != null">
<div>
<img src="./assets/images/pwa.png" alt="pwa logo" />
</div>
<div class="d-flex flex-column justify-content-center ms-3">
<div>Cool! You`re device and application support PWA.</div>
<div>
<button mat-raised-button color="primary" (click)="installPwa()">Install me</button>
</div>
</div>
</div>

And the last step — when the user decides to install the App, the user clicks on the button — we will trigger installation:

public async installPwa() {
if (this.deferredPrompt) {
// we use stored 'deferredPrompt' from 'beforeinstallprompt' listener
this.deferredPrompt.prompt();
const { outcome } = await this.deferredPrompt.userChoice;
console.log(`User response to the install prompt: ${outcome}`);
window.deferredPrompt = null;
} else {
console.error('nope, already installed')
}
}
Custom Installation — our own UI
Installation

Installation of PWA has been so far feature for which user must know about it — has a knowledge how to install. And frankly, it could have been quite easy overlooked/missed. With Custom Installation we can easily shift user focus to this feature and notify user about benefits of PWA.

See also an interesting article about Custom App installation.

Badges

Wouldn’t it be awesome if your application could show some “visual” notification about the count of TODOs in our application? Fortunately, we can use navigator (browser) API for badges. API is quite straightforward:

try {
await navigator.setAppBadge(countOfTodos);
console.debug('Badge set');
} catch (e) {
console.error('Cannot set badge', e);
}

The badge is a “bubble with icon or message” which we are used to seeing in chat applications or when applications require some attention.

Badges on desktop

Badges are another interesting step forward for PWAs application — we can easily simulate “native” web or mobile application feature for notifying user with important messages.

See also an exciting article about Badging API or documentation.

Link to repository

If you are interested in PWA and want to try it with Angular, you can try this repository. The repository contains all features covered in this article. Also, checkout branches that will guide you step-by-step on how to implement these features:

Responsive Web vs PWA vs Hybrid App vs Native Mobile app — which one use?

And this is an interesting question! Any ideas?! My personal opinion is:

  • If a mobile application “native-app like feeling”) is not required, still make a web application with a good, responsive web design (PWA could be enabled later, with small effort)
  • Suppose the application requires to have “pixel perfect” design. In that case, you expect heavy use of mobile hardware resources (games), or access to native mobile SDKs (camera features, …) — then use native Native Mobile App.
  • But if you need “something” between (offline mode with “native-app feeling”), which does not need to be distributed with the official store — use PWA.

And where are Hybrid Apps (ionic, react native, …)? They are, for me, equal to PWA, with the benefit of being able to distribute over stores but with a drawback of the new framework/new skills required in the team.

Thanks to Marek Vodicka for help with this article!


Progressive Web Apps was originally published in ableneo Technology on Medium, where people are continuing the conversation by highlighting and responding to this story.

Related