Progressive Web Apps
using the Angular Mobile Toolkit
Maxim Salnikov
Angular GDE
Automatic
Maxim Salnikov
-
Google Developer Expert in Angular
-
Angular Oslo meetup organizer
-
ngVikings conference organizer
Products from the future
UI Engineer at ForgeRock
Milestones of the web
AJAX
Static
Dynamic
RWD
PWA
Progressive Web App
... Progressive Web App can be seen as an evolving hybrid of regular web pages (or websites) and a mobile application
... a new software development methodology
10 characteristics
- Progressive
- Discoverable
- Linkable
- App-like
- Responsive
- Connectivity-independent
- Re-engageable
- Installable
- Fresh
- Safe
App Shell architecture
Service Worker API
Push API and Notifications API
Involved APIs
-
Service Worker API
-
Cache API
-
Fetch API
-
Notifications API
-
Push API
-
IndexedDB API
-
Promises
Mobile Toolkit
Where is --mobile?
The answer
No more
flag
--mobile
2 packages
@angular/service-worker
v1.0.0-beta.8 - Experimental service worker by the Angular Mobile team
@angular/app-shell
v0.1.0 - App Shell runtime library for Angular Progressive Web Apps
Service Worker
Angular Service Worker
NGSW
4 main parts
@angular/service-worker/bundles
@angular/service-worker/build
@angular/service-worker/companion
@angular/service-worker/worker
@angular/service-worker/plugins
NGSW installation
# First, install the Angular Service Worker
$ npm install --save @angular/service-worker
# Enable the SW registration + app shell in Angular CLI
$ ng set apps.0.serviceWorker=true
"apps": [
{
"serviceWorker": true
}
]
.angular-cli.json
App build
# NGSW works only in --prod mode
$ ng build --prod
<script src="sw-register.{HASH}.bundle.js"></script>
-
sw-register.{HASH}.bundle.js
-
worker-basic.min.js
-
ngsw-manifest.json
index.html
Static content caching
{
"static": {
"urls": {
"/index.html": "ae543...",
"/main.bundle.js": "9ff18...",
"/styles.bundle.css": "d6f44...",
"/assets/images/logo.png": "0e33a...",
...
}
}
}
ngsw-manifest.json
Route redirection
{
"routing": {
"index": "/index.html",
"routes": {
"/": {
"prefix": false
},
"/some/routes-group-prefix": {
"prefix": true
}
}
}
}
ngsw-manifest.json
Extending NGSW manifest
{
"static" : {
...autogenerated
}
}
{
"routing" : {...}
...
}
ngsw-manifest.json
Angular PWA
Static Content
Cache
External content caching
{
"external": {
"urls": [
{
"url": "https://fonts.gstatic.com/Roboto.ttf"
}
]
}
}
ngsw-manifest.json
Angular PWA
Static Content
Cache
External Content Cache
Dynamic content caching
{
"dynamic": {
"groups": [
{
"name": "api",
"urls": {...},
"cache": {...}
}
]
}
}
ngsw-manifest.json
Dynamic cache settings
cache: {
"optimizeFor": "freshness", // or 'performance'
"networkTimeoutMs": 200,
"maxAgeMs": 1000,
"maxEntries": 2,
"strategy": "fifo" // or 'lru', 'lfu'
}
urls: {
"/api/breakingnews": {
"match": "prefix"
}
},
ngsw-manifest.json
Coming soon
Angular PWA
Static Content
Cache
External Content Cache
Dynamic Content
Cache
Companion
import {NgServiceWorker} from '@angular/service-worker';
constructor(public sw: NgServiceWorker) {}
app.component.ts
import {ServiceWorkerModule} from '@angular/service-worker'
imports: [
...
ServiceWorkerModule
]
app.module.ts
Gentle app update flow
sw.updates.subscribe(event => {
if (event.type === 'pending') {
// Ask user if they want to update?
if (agreeToUpdate) {
sw.activateUpdate(event.version);
}
} else {
// event.type === 'activation'
// NGSW is now serving a new version
location.reload();
}
});
app.component.ts
Push notifications
Backend
Notification
Push Service
NGSW
App
Backend
Push Service
App
Subscription
Sending a notification
Push settings
{
"push": {
"showNotifications": true,
"backgroundOnly": false
}
}
ngsw-manifest.json
Push subscription
constructor(public sw: NgServiceWorker) {}
sw.registerForPush().subscribe(subscriptionObject => {
// Send subscription data to the server
});
import {NgServiceWorker} from '@angular/service-worker';
push.component.ts
sw.push.subscribe(notificationPayload => {
// Process notification data
});
Angular PWA
Static Content
Cache
External Content Cache
Push
Dynamic Content
Cache
Basic Service Worker
import {bootstrapServiceWorker} from '@angular/service-worker/worker';
import {StaticContentCache} from '@angular/service-worker/plugins/static';
...
bootstrapServiceWorker({
manifestUrl: '/ngsw-manifest.json',
plugins: [
StaticContentCache(),
...
]
});
worker/builds/basic.ts
Extending functionality
import {bootstrapServiceWorker} from '@angular/service-worker/worker';
import {StaticContentCache} from '@angular/service-worker/plugins/static';
...
import {MyCustomPlugin} from './plugins/my-custom-plugin';
bootstrapServiceWorker({
manifestUrl: '/ngsw-manifest.json',
plugins: [
StaticContentCache(),
...
MyCustomPlugin()
]
});
worker-custom.js
Automatic PWA
{
"static": {...},
"routing": {...},
"external": {...},
"dynamic": {...},
"push": {...}
}
ngsw-manifest.json
Angular PWA
Static Content
Cache
External Content Cache
Push
Dynamic Content
Cache
Automatically
Thank you!
@webmaxru
Maxim Salnikov
Automatic Progressive Web Apps using the Angular Mobile Toolkit
By Maxim Salnikov
Automatic Progressive Web Apps using the Angular Mobile Toolkit
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 favorite tools to build installable, re-engageable, connectivity independent apps, that can bring native-like performance and user experience.
- 6,066