Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PWA Deep Dive: Offlineanwendungen im Griff

PWA Deep Dive: Offlineanwendungen im Griff

Zentrale Eigenschaft jeder Progressive Web App (PWA) ist die Verbindungsunabhängigkeit. Dank dem Service Worker funktioniert die App auch dann, wenn der Anwender gerade offline ist: im Tunnel, im Park oder im Dschungel. Bei der Generierung eines Service Workers hilft das Toolkit Workbox. Anwenderdaten werden hingegen in der Browserdatenbank IndexedDB hinterlegt. Wo Daten offline gehalten werden, müssen aber auch deren Synchronisierung und Konfliktauflösung in der Architektur bedacht werden. Christian Liebel zeigt Ihnen die Mechanik hinter dem Service-Worker-Cache und der Browserdatenbank IndexedDB, sodass es auch Ihre PWA mit den nativen Gegenstücken problemlos aufnehmen kann.

Christian Liebel
PRO

April 22, 2020
Tweet

More Decks by Christian Liebel

Other Decks in Programming

Transcript

  1. PWA Deep Dive
    Offlineanwendungen im Griff
    Christian Liebel
    @christianliebel
    Consultant

    View Slide

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

    View Slide

  3. PWA Deep Dive
    Offlineanwendungen im Griff

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  7. 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

    View Slide

  8. 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

    View Slide

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

    View Slide

  10. Locking
    Pessimistic
    - System locks access to
    resource if it is used by
    another user
    - No conflicts
    - Users don’t like this (offline =
    no locking possible!)
    Optimistic
    - Users can access arbitrary
    resources anytime
    - Requires data synchronization
    & conflict resolution
    (strategies depend on domain)
    PWA Deep Dive
    Offlineanwendungen im Griff
    Offline First

    View Slide

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

    View Slide

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

    View Slide

  13. 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

    View Slide

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

    View Slide

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

    View Slide

  16. 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

    View Slide

  17. Debugging
    PWA Deep Dive
    Offlineanwendungen im Griff
    Service Worker

    View Slide

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

    View Slide

  19. 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

    View Slide

  20. 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)

    View Slide

  21. 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

    View Slide

  22. 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

    View Slide

  23. 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

    View Slide

  24. Debugging
    PWA Deep Dive
    Offlineanwendungen im Griff
    Cache API

    View Slide

  25. 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/

    View Slide

  26. 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

    View Slide

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

    View Slide

  28. 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

    View Slide

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

    View Slide

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

    View Slide

  31. 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

    View Slide

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

    View Slide

  33. 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

    View Slide

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

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

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

    View Slide

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

    View Slide

  39. 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

    View Slide

  40. 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

    View Slide

  41. …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

    View Slide

  42. IndexedDB Debugging
    PWA Deep Dive
    Offlineanwendungen im Griff
    Dexie.js

    View Slide

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

    View Slide

  44. 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

    View Slide

  45. 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

    View Slide

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

    View Slide