Aliaksei Kuncevič

Software Engineer/Angular Consultant



PWA with Angular

by Aliaksei Kuncevič

What is

Progressive web apps (PWAs) are web applications that are regular web pages or websites, but can appear to the user like traditional applications or native mobile applications. The application type attempts to combine features offered by most modern browsers with the benefits of mobile experience.

(c) Wikipedia

modern browser features

whatwebcando.today

what web can do


whatwebcando.today

The PWA King

Edge

Firefox

Safari

A service worker is an event-driven worker registered against an origin and a path. It takes the form of a JavaScript file that can control the web page/site it is associated with, intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control over how your app behaves in certain situations.

Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available).

(c) Mozilla

Service Worker

Use Cases

  • Caching app bundles, assets and api calls
  • Background data sync/preload/offline
  • Push Notifications

Browsers Support

caniuse.com/#search=serviceworker

PWA experiences

  • Reliable (load instantly)
  • Engaging (feel like a natural app)
  • Fast (respond quickly to user interactions)

Reliable


Cache, network state

Engaging


Installable, user home screen, push notifications

Fast


53% of users will abandon a site if it takes longer than 3 seconds to load

Angular


@angular/service-worker

Angular PWA


angular.io/guide/service-worker-intro

Developer experience

  • No need to implement service worker yourself
  • Angular-aware service worker
  • Config-driven
  • Refreshing in all opened browser tabs

Angular cli

Features

  • PWA Support (CLI v.1.6+)
  • Scaffolding (minimize boilerplate)
  • Run unit and e2e tests
  • Linting (tslint, codelyzer)
  • Transpiling TypeScript
  • Compress assets
  • Compiling LESS/SASS
  • Webpack (dev, prod builds, code split)
  • Threes Shaking
  • Build Optimizeration/Minification
  • Produce CSS and JS bundles

how to start

npm install -g @angular/cli
ng new my-app --service-worker
cd my-app
ng build --prod
ng add pwa //coming soon
angular.io/guide/service-worker-intro

build output

Code example

import { SwPush } from '@angular/service-worker';

@Component({
  selector: 'app-control-push',
  templateUrl: './control-push.component.html',
  styleUrls: ['./control-push.component.css']
})
export class ControlPushComponent {
  constructor(private swPush: SwPush) { }

  showMessages() {
    this.swPush.messages
      .subscribe(message => {
        console.log('[App] Push message received', message);
      });
  }
}

Configuraton

{
  "index": "/index.html",
  "appData": {
    "name": "app v1",
    "description": "sample app"
  },
  "assetGroups": [{
    "name": "app",
    "installMode": "prefetch",
    "resources": {
      "files": [
        "/favicon.ico",
        "/index.html"
      ],
      "versionedFiles": [
        "/*.bundle.css",
        "/*.bundle.js",
        "/*.chunk.js"
      ]
    }
  }, {
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {
      "files": [
        "/assets/**"
      ]
    }
  }, {
    "name": "fonts",
    "resources": {
      "urls": [
        "https://fonts.googleapis.com/**",
        "https://fonts.gstatic.com/**"
      ]
    }
  }],
  "dataGroups": [{
      "name": "api-timeline",
      "urls": [
        "/timeline"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "2d",
        "timeout": "10s"
      }
    },
    {
      "name": "api-history",
      "urls": [
        "/history"
      ],
      "cacheConfig": {
        "strategy": "performance",
        "maxSize": 100,
        "maxAge": "5d"
      }
    }
  ]
}
ngsw-config.json

debug

  • http://localhost:[your-port]/ngsw/state

debug info

Lighthouse

developers.google.com/web/tools/lighthouse

Lighthouse Report


Hacker News readers as Progressive Web Apps
hnpwa.com

demo

remove

  • ng set apps.0.serviceWorker=false
  • Make sure server respond with 404 for ngsw.json

fetch manifest

async fetchLatestManifest() {
  const res = await this.safeFetch(
    this.adapter.newRequest('ngsw.json?ngsw-cache-bust=' + Math.random())
  );
  if (!res.ok) {
    if (res.status === 404) {
      await this.deleteAllCaches();
      this.scope.registration.unregister();
    }
    throw new Error('Manifest fetch failed!');
  }
  this.lastUpdateCheck = this.adapter.time;
  return res.json();
}

ngsw code

NY

questions ?


@kuncevic