Maxim Salnikov
Angular GDE
How to create an Angular Progressive Web App?
Progressive web apps use modern web APIs along with traditional progressive enhancement strategy to create cross-platform web applications.
Dev builds
Service Worker
API
Web App Manifest
<script />
$ ng new myPWA --mobile
$ ng new myPWA --service-worker
$ ng new myPWA
$ ng add @angular/pwa --project=myPWA
$ ng build --prod
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:
$ ng set apps.0.serviceWorker=true
$ npm install @angular/service-worker --save
node_modules/@angular...
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
...
@NgModule({
...
imports: [
...
]
})
export class AppModule { }
ServiceWorkerModule.register('/ngsw-worker.js',
{ enabled: environment.production }),
{
"index": "/index.html",
"assetGroups": [...],
"dataGroups": [...]
}
{
"name": "app",
"installMode": "prefetch",
"resources": {...}
}
"resources": {
}
"versionedFiles": [
"/*.bundle.css",
"/*.bundle.js",
"/*.chunk.js"
],
"files": [
"/favicon.ico",
"/index.html"
],
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {...}
}
"resources": {
}
"files": [
"/assets/**"
],
"urls": [
"https://fonts.googleapis.com/**",
"https://fonts.gstatic.com/**"
]
{
"name": "api-freshness",
"urls": [
"/api/breakingnews/**"
],
}
"cacheConfig": {
"strategy": "freshness",
"maxSize": 10,
"maxAge": "12h",
"timeout": "10s"
}
{
"name": "api-performance",
"urls": [
"/api/archive/**"
],
}
"cacheConfig": {
"strategy": "performance",
"maxSize": 100,
"maxAge": "365d"
}
{
"version": 1,
"name": "api-performance",
"urls": [
"/api/**"
],
...
}
{
"version": 2,
"name": "api-performance",
"urls": [
"/api/**"
],
...
}
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()
})
})
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
})
}
{
"notification": {
}
}
"title": "Very important notification",
"body": "Angular Service Worker is cool!",
"icon": "https://angular.io/assets/logo.png",
"actions": [
{
"action": "gocheck",
"title": "Go and check"
}
],
...
ng set apps.0.serviceWorker=false
ng build --prod
...deploy
rm dist/ngsw.json
...deploy
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'); });
});