in the #YearOfPWA

Maxim Salnikov

@webmaxru

Progressive

Angular Apps

How to create Angular Progressive Web App?

Using the native tools

Maxim Salnikov

  • Google Developer Expert, Microsoft MVP

  • Angular Oslo / PWA Oslo meetups organizer

  • ngVikings conference organizer

  • ngCommunity maintainer

Products from the future

UI Engineer at ForgeRock

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

Flagged

OS

#YearOfPWA

UX advantages?

Smart networking + Offline

Proper app experience

Staying notified

Other cool things

}

Service Worker API

Web App Manifest

Service worker options

  • Code service worker manually

  • Use framework-agnostic PWA libraries

  • Use Angular Service Worker

NGSW

Automate it!

Automation

  •   Scaffolding

  •   Building

  •   Running

1

2

3

Schematics

Angular CLI

NGSW

PWA MVP

Recipe #1

Minimal PWA

  • Served via HTTPS

  • Responsive, fast, cross-browser

  • App metadata provided

  • App loads while offline

$ ng add @angular/pwa

Apply PWA schematics

1

  • Add service worker registration code to the root module

  • Generate default service worker configuration file

  • Generate and link default Web App Manifest

  • Generate default icons set

  • Enable build support in Angular CLI config

$ ng build --prod

Build

ngsw-worker.js

ngsw.json

dist/project-name

safety-worker.js

assets/icons/*.png

manifest.json

worker-basic.min.js

2

Running and auditing

$ ng serve

Static dev webserver

  • serve

  • superstatic

  • lite-server

$ ng serve --prod

Dev Tools / Audit / PWA

Automated app shell actions

  • Generate assets (+ hashes) list

 

2

3

  • Load and cache assets

  • Set up routing

  • Serve assets from the Cache Storage

  • Load and cache the updated assets

  • Inform the application about the update (next recipe)

NGSW configuration file

ngsw-config.json

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

App shell

assetGroups

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

App shell resources

assetGroups / "app" / resources

"resources": {







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

Hint: Automate server-side rendering

Angular Universal PWA Kit

$ ng add @ng-toolkit/universal

Run before adding @angular/pwa

Important!

src/

assets/icons/*.png

manifest.json

index.html / <meta name="theme-color" ...>

To be customized

App update notification

Recipe #2

App version updates

v1

v2

v1

v1

v2

Server

Browser

v2

Using SwUpdate service

import { SwUpdate } from '@angular/service-worker';
constructor(updates: SwUpdate) {}
this.updates.available.subscribe(event => {




})

updates.component.ts

    if (confirm(`New Version is available! OK to refresh`)) {
            window.location.reload();
    }

Hint: Provide a version description

{
  "appData": {
    "versionMessage": "New version: Push notifications added!"
  },
  ...
}
let appData = event.available.appData
let versionMessage = appData ? appData['versionMessage'] 
                             : 'New version is available!'

ngsw-config.json

updates.component.ts

Adding more resources to the App Shell

Recipe #3

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/**"
    ]

Removing routes from NGSW control

Recipe #4

ngsw-config.json

"navigationUrls": [
  '/**',
  '!/**/*.*',
  '!/**/*__*',
  '!/**/*__*/**',



]
  '!/**/login*',
  '!/**/account*'

What to redirect to index.html

Data requests caching

Recipe #5

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: Support API versioning

dataGroups

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

Subscribing for the Push notifications

Recipe #6

Push notifications

import { SwPush } from '@angular/service-worker';
constructor(push: SwPush) {}
subscribeToPush() {
  this.push.requestSubscription({
    serverPublicKey: this.VAPID_PUBLIC_KEY
  })
    .then(pushSubscription => {
      // Pass subscription object to the 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"
      }
    ],
    ...

In case of emergency

Recipe #7

Last resort

cp safety-worker.js ngsw-worker.js
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

A gentle way

rm ngsw.json

Disadvantages

  • Angular Service Worker always works as the main service worker of the whole application

  • There is no [documented] way to extend the functionality

 

Advantages

  • Minimal PWA goes out-of-the-box

  • Essential features are codeless

  • Doing things in Angular way

  • Advanced integrity checks + fallback support

  • 1700+ developers

  • Major browsers/frameworks/libs reps

Thank you!

Maxim Salnikov

@webmaxru

Questions?

Progressive Angular Apps in the #YearOfPWA

By Maxim Salnikov

Progressive Angular Apps in the #YearOfPWA

Many web developers agree in opinion that 2018 will open a new milestone for the web. This will be a year of the really broad adoption of progressive web apps by all the parties: browser vendors, developers, users. What does Angular team contribute to this movement? Let’s have a deep look at the latest and greatest Angular Service Worker. We skip the documentation-like feature listing and look beyond: practical applications, current browsers support, known limitations and lots of useful insights and tips & tricks. Example of server-side rendered and cached application shell is included! As a practical outcome of the session, you will know how to create a truly progressive Angular app, while saving time and nerves by avoiding some deep pitfalls waiting for you in seemingly simple (but quite tricky when in comes to the real world use cases) PWA idea.

  • 1,493