using Angular Service Worker

Maxim Salnikov

Angular GDE

Automatic

Progressive Web Apps 

How to create an Angular Progressive Web App?

Natively & naturally

Maxim Salnikov

  • Full-Stack Engineer at ForgeRock

  • PWAngelist / trainer

  • LondonPWA and OsloPWA meetups organizer

  • ngVikings conference organizer

After all, what is PWA?

Progressive web apps use modern web APIs along with traditional progressive enhancement strategy to create cross-platform web applications.

These apps work everywhere and provide several features that give them the same user experience advantages as native apps.

Cross-platform?

Browser

Desktop

Mobile

App store?

Dev builds

During last two weeks

UX advantages?

Working offline

Proper app experience

Smarter networking

Staying notified

}

Service Worker

API

Web App Manifest

  • 1300+ developers

  • Major browsers/frameworks/libs reps

+

=

<script />

+

=

Angular Service Worker

NGSW

Generate a new Angular PWA

$ ng new myPWA --mobile
  • Angular CLI < 1.6

  • Angular Service Worker β

Yesterday

Angular Mobile Toolkit

Generate a new Angular PWA

$ ng new myPWA --service-worker
  • Angular CLI 1.6-1.7 

  • Angular Service Worker 5

Today

Generate a new Angular PWA

$ ng new myPWA
  • Angular CLI 6

  • Angular Service Worker 6

  • Web App Manifest

  • @Schematics

Tomorrow

$ ng add @angular/pwa --project=myPWA

Building Angular PWA

$ ng build --prod

ngsw-worker.js

ngsw.json

dist/

Hint #1: Checking the status

https://yourwebsite.com/ngsw/state

NGSW Debug Info:

Driver state: NORMAL ((nominal))
Latest manifest hash: cd4716ff2d3e24f4292010c929ff429d9eeead73
Last update check: 9s215u

=== Version 34c3fd2361735b1330a23c32880640febd059305 ===

Clients: 7eb10c76-d9ed-493a-be12-93f305394a77

=== Version cd4716ff2d3e24f4292010c929ff429d9eeead73 ===

Clients: ee22d69e-37f1-439d-acd3-4f1f366ec8e1

=== Idle Task Queue ===
Last update tick: 4s602u
Last update run: 9s222u
Task queue:


Debug log:

Adding NGSW to the existing app

$ ng set apps.0.serviceWorker=true
$ npm install @angular/service-worker --save

1. Install the package

2. Enable build support

3. Register NGSW for your app

4. Create configuration file

Service worker build support in the CLI

Build

Copy

src/ngsw-config.json

dist/ngsw.json

ngsw-worker.js

dist/

node_modules/@angular...

Can be npm-scripted for legacy Angular CLIs!

Registering NGSW

import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
...
@NgModule({
  ...
  imports: [
    ...


  ]
})
export class AppModule { }
    ServiceWorkerModule.register('/ngsw-worker.js',
        { enabled: environment.production }),

app.module.ts

NGSW configuration file

src/ngsw-config.json

{
  "index": "/index.html",
  "assetGroups": [...],
  "dataGroups": [...]
}

Working offline

Proper app experience

Smarter networking

Staying notified

App shell

assetGroups

{
    "name": "app",
    "installMode": "prefetch",
    "resources": {...}
}

App shell resources

assetGroups / "app" / resources

"resources": {









}
    "versionedFiles": [
      "/*.bundle.css",
      "/*.bundle.js",
      "/*.chunk.js"
    ],
    "files": [
      "/favicon.ico",
      "/index.html"
    ],

App shell / on-demand

assetGroups

{
    "name": "assets",
    "installMode": "lazy",
    "updateMode": "prefetch",
    "resources": {...}
}

App shell / on-demand

assetGroups / "assets" / resources

"resources": {








}
    "files": [
      "/assets/**"
    ],
    "urls": [
        "https://fonts.googleapis.com/**",
        "https://fonts.gstatic.com/**"
    ]

Runtime caching

dataGroups

{
    "name": "api-freshness",
    "urls": [
      "/api/breakingnews/**"
    ],






}
    "cacheConfig": {
      "strategy": "freshness",
      "maxSize": 10,
      "maxAge": "12h",
      "timeout": "10s"
    }

Runtime caching

dataGroups

{
    "name": "api-performance",
    "urls": [
      "/api/archive/**"
    ],






}
    "cacheConfig": {
      "strategy": "performance",
      "maxSize": 100,
      "maxAge": "365d"
    }

Hint #2: Support API versioning

dataGroups

{
    "version": 1,
    "name": "api-performance",
    "urls": [
      "/api/**"
    ],
    ...
}
{
    "version": 2,
    "name": "api-performance",
    "urls": [
      "/api/**"
    ],
    ...
}

App version updates

v1

v2

v1

v1

v2

Server

Browser

v2

Hint #3: Notify about updates

import { SwUpdate } from '@angular/service-worker';
constructor(private swUpdate: SwUpdate) {}
this.swUpdate.available.subscribe(event => {
  let snackBarRef = this.snackBar
    .open('Newer version of the app is available', 'Refresh');

  snackBarRef.onAction().subscribe(() => {
    window.location.reload()
  })
})

updates.component.ts

Working offline

Proper app experience

Smarter networking

Staying notified

Push notifications

import { SwPush } from '@angular/service-worker';
constructor(private swPush: SwPush) {}
subscribeToPush() {
  this.swPush.requestSubscription({
    serverPublicKey: this.VAPID_PUBLIC_KEY
  })
    .then(pushSubscription => {
      // Pass subscription object to backend
    })
}

push.component.ts

Push notifications / send

{
  "notification": {










  }
}

server-side.js / sendNotification payload

    "title": "Very important notification",
    "body": "Angular Service Worker is cool!",
    "icon": "https://angular.io/assets/logo.png",
    "actions": [
      {
        "action": "gocheck",
        "title": "Go and check"
      }
    ],
    ...

Hint #4: Kill switch

1. Long way

ng set apps.0.serviceWorker=false
ng build --prod
...deploy

2. Short way

rm dist/ngsw.json
...deploy

Hint #4: Kill switch

3. Proper way

cp dist/safety-worker.js dist/ngsw-worker.js
...deploy
self.addEventListener('install', e => { self.skipWaiting(); });

self.addEventListener('activate', e => {
  e.waitUntil(self.clients.claim());
  self.registration.unregister().then(
      () => { console.log('Unregistered old service worker'); });
});

safety-worker.js

Main available features

App Shell

Runtime Caching

Push Notifications

Smart Updates

Angular Service Worker advantages

  • Essential features are config-driven

  • Decoupled updates model

  • Integrity checks

  • Doing things in Angular way

Thank you!

@webmaxru

Maxim Salnikov

Questions?

Made with Slides.com