Slide 1

Slide 1 text

PWA Deep Dive Offlineanwendungen im Griff Christian Liebel @christianliebel Consultant

Slide 2

Slide 2 text

PWA Deep Dive Offlineanwendungen im Griff Responsive Linkable Discoverable Installable App-like Connectivity Independent Fresh Safe Re-engageable Progressive

Slide 3

Slide 3 text

PWA Deep Dive Offlineanwendungen im Griff

Slide 4

Slide 4 text

Service Worker & Cache API Source Files & Assets App & IndexedDB Structured Data PWA Deep Dive Offlineanwendungen im Griff Connectivity Independent

Slide 5

Slide 5 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 6

Slide 6 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 7

Slide 7 text

Offline Capability Challenge: Connection strength varies a lot (especially en route) Lie-Fi: Connection strength of a public WiFi is weak or even completely offline Goal: App works offline or with a weak connection at least within the possibilities (e.g. OneNote) PWA Deep Dive Offlineanwendungen im Griff Offline First

Slide 8

Slide 8 text

Principle PWA Deep Dive Offlineanwendungen im Griff Offline First - Draft and implement offline support first - Think about synchronization & conflicts - Don’t treat offline as an error - Make offline the default - Everything must be offline capable

Slide 9

Slide 9 text

PWA Deep Dive Offlineanwendungen im Griff Offline First System Website HTML/JS Local storage Central adapter Remote storage Server Internet

Slide 10

Slide 10 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 11

Slide 11 text

Key Technology Service Worker Service Worker Internet Website HTML/JS Cache fetch Offlineanwendungen im Griff PWA Deep Dive

Slide 12

Slide 12 text

Worker snippet is executed in an own thread Worker can’t manipulate the parent document’s DOM Communication via thin API (postMessage) Acts as a controller/proxy/interceptor Performs background tasks Has to be installed before usage Relation: Scope (origin + path) Lifetime: Unrelated to tab/window PWA Deep Dive Offlineanwendungen im Griff Service Worker

Slide 13

Slide 13 text

Lifecycle PWA Deep Dive Offlineanwendungen im Griff Service Worker Installing Parsed Error Activated Idle Terminated fetch/ message

Slide 14

Slide 14 text

Platform Support Service Worker Offlineanwendungen im Griff PWA Deep Dive 17 11.1 44 40 4.1 Chrome 40 11.3

Slide 15

Slide 15 text

Basic Implementation navigator.serviceWorker.register('sw.js') .then(subscription => console.log(subscription)) .catch(err => console.error('Fehler', err)); self.addEventListener('install', event => {}); self.addEventListener('activate', () => {}); self.addEventListener('fetch', event => {}); PWA Deep Dive Offlineanwendungen im Griff Service Worker LIVE DEMO

Slide 16

Slide 16 text

Debugging PWA Deep Dive Offlineanwendungen im Griff Service Worker

Slide 17

Slide 17 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 18

Slide 18 text

Introduction Cache: Key-value storage Key: HTTP(S) request, value: HTTP(S) response Survives browser restarts (Safari: unused caches are cleared “after a few weeks”) Can be accessed from both service worker and website Isolated per origin (protocol + hostname + port) Multiple named caches per origin Cache operations are asynchronous (Promises) PWA Deep Dive Offlineanwendungen im Griff Cache API

Slide 19

Slide 19 text

Usage 1. Open a cache 2. Store/read responses from the cache PWA Deep Dive Offlineanwendungen im Griff Cache API await caches.open('images') await cache.put(req, res) await cache.add(req) await cache.match(req)

Slide 20

Slide 20 text

and Service Worker PWA Deep Dive Offlineanwendungen im Griff Cache API Installing Parsed Error Activated Idle Terminated fetch/ message Install cache content Remove old caches Deliver from cache

Slide 21

Slide 21 text

Adding Requests to The Cache self.addEventListener('install', event => { event.waitUntil( caches.open('pwa-demo-v1') .then(cache => cache.addAll(['/', '/index.html'])) .then(() => self.skipWaiting()) ); }); PWA Deep Dive Offlineanwendungen im Griff Cache API LIVE DEMO

Slide 22

Slide 22 text

Delivering from The Cache self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => response || fetch(event.request)) ); }); PWA Deep Dive Offlineanwendungen im Griff Cache API LIVE DEMO

Slide 23

Slide 23 text

Debugging PWA Deep Dive Offlineanwendungen im Griff Cache API

Slide 24

Slide 24 text

Caching Strategies 1. Cache only 2. Network only 3. Cache falling back to network 4. Cache & network race 5. Network falling back to cache 6. Cache then network 7. Generic Fallback 8. Service-Worker-side templating PWA Deep Dive Offlineanwendungen im Griff Cache API https://jakearchibald.com/2014/offline-cookbook/

Slide 25

Slide 25 text

Use Cases Service Worker - everything that’s part of a website/app version - application source files - assets Application - dynamic content known during runtime - “read later”, profile images, … - lookup without fetch PWA Deep Dive Offlineanwendungen im Griff Cache API

Slide 26

Slide 26 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 27

Slide 27 text

Overview Toolchain by Google: Service Worker generator and runtime library Automatically creates a Service Worker implementation for you Can extend an existing Service Worker implementation with caching Command line tool: workbox npm i -g workbox-cli PWA Deep Dive Offlineanwendungen im Griff Workbox

Slide 28

Slide 28 text

Commands workbox wizard workbox generateSW workbox injectManifest PWA Deep Dive Offlineanwendungen im Griff Workbox LIVE DEMO

Slide 29

Slide 29 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 30

Slide 30 text

PWA Setup Angular supports service worker and cache manifest generation (for productive builds only) npm i -g @angular/cli ng new myApp cd myApp ng add @angular/pwa ng build --prod PWA Deep Dive Offlineanwendungen im Griff Angular LIVE DEMO

Slide 31

Slide 31 text

Update Process PWA Deep Dive Offlineanwendungen im Griff Angular V1 V2 V2 V1 V1 V2 Server Browser

Slide 32

Slide 32 text

SwUpdate The SwUpdate service provides an available observable that fires when there’s an update. As a result, the user can be prompted to reload the website. PWA Deep Dive Offlineanwendungen im Griff Angular

Slide 33

Slide 33 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 34

Slide 34 text

Motivation The web platform has different techniques to store arbitrary data (e.g. application state) offline: • Web Storage API (Local Storage/Session Storage—synchronous!) • Cookies (inconvenient) • IndexedDB PWA Deep Dive Offlineanwendungen im Griff IndexedDB

Slide 35

Slide 35 text

Overview Indexed Database (IndexedDB) is a database in the browser capable of storing structured data in tables with keys and value Data is stored permanently (survives browser restarts) Service Worker and website share access to the same IndexedDB database (e.g. for synchronization purposes) PWA Deep Dive Offlineanwendungen im Griff IndexedDB

Slide 36

Slide 36 text

Browser Support PWA Deep Dive Offlineanwendungen im Griff IndexedDB 10 7.1 4 11

Slide 37

Slide 37 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 38

Slide 38 text

Overview Dexie is a minimalistic wrapper for IndexedDB Operations are based on promises instead of callbacks Near native performance (also for bulk inserts) Open-source PWA Deep Dive Offlineanwendungen im Griff Dexie.js

Slide 39

Slide 39 text

Table API const table = db.table('todos'); table.toArray() // get all items as an array table.add() // insert an object table.put() // update or insert an object table.filter(i => i.id !== 3) // apply JS filter on value table.where({ name: 'Peter' }) // query items by key PWA Deep Dive Offlineanwendungen im Griff Dexie.js

Slide 40

Slide 40 text

…and TypeScript class MyAppDatabase extends Dexie { todos: Dexie.Table; constructor () { super('MyTodoDatabase'); this.version(1).stores({ todos: '++id', }); this.todos = this.table('todos'); } } PWA Deep Dive Offlineanwendungen im Griff Dexie.js LIVE DEMO

Slide 41

Slide 41 text

IndexedDB Debugging PWA Deep Dive Offlineanwendungen im Griff Dexie.js

Slide 42

Slide 42 text

Offline First Service Worker Cache API Workbox Angular Demo App IndexedDB Dexie.js Dexie.js Migrations PWA Deep Dive Offlineanwendungen im Griff Talking Points

Slide 43

Slide 43 text

Migrations db.version(1).stores({ friends: "++id,name,age" }); db.version(2).stores({ friends: "++id,name,birthdate" }).upgrade(trans => { const YEAR = 365 * 24 * 60 * 60 * 1000; return trans.friends.toCollection().modify(friend => { friend.birthdate = new Date(Date.now() - (friend.age * YEAR)); delete friend.age; }); }); PWA Deep Dive Offlineanwendungen im Griff Dexie.js

Slide 44

Slide 44 text

Make use of the Offline First pattern Use Cache API for HTTPS requests Use IndexedDB for structured data Use Service Workers for initial caching and delivering cached content Think about data synchronization & conflict handling for structured data Make your users happy! PWA Deep Dive Offlineanwendungen im Griff Summary

Slide 45

Slide 45 text

Thank you! Off next: Q&A Christian Liebel @christianliebel [email protected]