using Angular Service Worker

Maxim Salnikov

Angular GDE

Automatic

Progressive Web Apps 

How to create an Angular Progressive Web App?

Natively

Maxim Salnikov

  • Full-stack engineer at ForgeRock

  • Google Developer Expert in Angular

  • PWA evangelist / trainer

  • ngVikings conference organizer

ngVikings.org

  • All sides of Angular ecosystem presented by international experts

  • 100% community-driven event from developers for developers

  • Only technical and practical Angular content

March 1-2, Helsinki, Finland

Progressive Web App

... attempts to combine features offered by most modern browsers with the benefits of mobile experience

... web apps that use the latest web technologies.

10 characteristics

  • Progressive

  • Discoverable

  • Linkable

  • App-like

  • Responsive

  • Connectivity-independent

  • Re-engageable

  • Installable

  • Fresh

  • Safe

Service worker

Logically

Physically

JS

-file

App

Service worker

Angular Service Worker

Wait a sec!

  • 1000+ developers

  • Major browsers/frameworks/libs reps

Generate a new Angular PWA

$ ng new myProgressiveApp --service-worker

Starting from Angular CLI 1.6

$ ng build --prod

ngsw-worker.js

ngsw.json

dist/

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 Angular CLI 1.5!

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": [...]
}

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"
    }

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"
      }
    ],
    ...

App version updates

v1

v2

v1

v1

v2

Server

Browser

v2

Check for 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

Hint #1: Debugging update flow

1. Keep DevTools closed & wait...

3. Use code snippets 

Every time the Angular service worker starts, it checks for updates to the app by looking for updates to the ngsw.json manifest.

this.swUpdate.available.subscribe(event => {});

Behaviour to be changed

2. Unload browser from memory

this.swUpdate.checkForUpdate()

- OR -

Hint #2: 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:

Hint #3: Kill switch

1. Long way

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

2. Short way

rm dist/ngsw.json
...deploy

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

On the roadmap

  • Integration with server-side rendering (app-shell)

  • Better debugging support

  • Make Angular app progressive by default

  • Documentation!

Thank you!

@webmaxru

Maxim Salnikov

Questions?

Automatic Progressive Web Apps using Angular Service Worker

By Maxim Salnikov

Automatic Progressive Web Apps using Angular Service Worker

Progressive Web Apps are the next big thing for the web. They combine the advantages of two platforms: searchability and shareability of the web with capabilities and performance of native mobile. As a result, web developers can use their favourite tools to build installable, re-engageable, connectivity independent apps, that can bring native-like performance and user experience. The Angular Service Worker makes it easy to get started building PWA. It’s developed to automate main routines and provide us with some nice tools to control the progressive app behaviour. During this practical session, we'll have a look at NGSW’s main components, and how they take our web app to the next level. With just some simple updates we’ll get installable, offline-capable, mobile-network-friendly Angular app re-engaging users by push-notifications.

  • 4,257