Introduction to
Progressive Web Apps

Agenda

  • Introduction
  • Service Workers
  • Caching options
  • Storage
  • Push Notification
  • Tooling

Current State of Mobile Web

  • Responsive Web Design
  • Mobile first
  • Mobile version of web page

in 2017 it's not enough...

We want to web apps that

  • always work despite of conectivity
    status
  • reduce loading time
  • are proactive

in marketing jargon

  • Reliable
  • Fast
  • Engaging

Progressive Web Apps

  • is a new way to deliver amazing user experiences on the web. Google
  • is term used to denote a new software development methodology. Unlike traditional applications, progressive web apps are a hybrid of regular web pages (or websites) and a mobile application (...).Wikipedia
  • are like good old web sites but better. In a modern browser they exhibit super–powersMozilla

Why should we care

Nine talks during Google I/0 2016 and seven during Google I/O 2017

PWA Components

  • Service Worker
  • manifest.json
  • app shell

Service Worker

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. Today, they already include features like push notifications and background sync. In the future service workers will support other things like periodic sync or geofencing.

Developers Google

manifest.json

 {
   "short_name": "AirHorner",
   "name": "Kinlan's AirHorner of Infamy",
   "icons": [{                 
          "src": "launcher-icon-1x.png",
          "type": "image/png",
          "sizes": "48x48"
          },                        
          {
           "src": "launcher-icon-4x.png",
           "type": "image/png",
           "sizes": "192x192"
          }],                
   "start_url": "index.html?launcher=true"
}             

App shell

An application shell (or app shell) architecture is one way to build a Progressive Web App that reliably and instantly loads on your users' screens, similar to what you see in native applications.

The app "shell" is the minimal HTML, CSS and JavaScript required to power the user interface and when cached offline can ensure instant, reliably good performance to users on repeat visits. This means the application shell is not loaded from the network every time the user visits. Only the necessary content is needed from the network.

Developers Google

Long Story Short

Progressive Web Apps are

  • websites / webapps
  • with some new features
  • with mobile App use and feel
  • framework agnostic

Example

taken from Google Web Fundamentals

Closer look to Service Workers

Workers

  • Isolated thread
  • Code contained in separate file (async download)
  • Communication via message passing - postMessage()
  • Messages copied, not shared
  • Same Origin

worker example

main.js

    var worker = new Worker('task.js');
    worker.addEventListener('message', function(e) {
    console.log('Worker said: ', e.data);
    }, false);

    worker.addEventListener('error', function(e){
    console.log('ERROR: Line', e.lineno, 'in', 
      e.filename, ':', e.message);
    }, false);

    worker.postMessage('Hello World'); // Send data to our worker.

task.js

    self.addEventListener('message', function(e) {
        self.postMessage(e.data);
     }, false);     

Features Available to Workers

  • The navigator object
  • The location object (read-only)
  • XMLHttpRequest
  • setTimeout()/clearTimeout() and setInterval()/clearInterval()
  • The Application Cache
  • Importing external scripts using the importScripts() method
  • Spawning other web workers

Workers do NOT have access to:

  • The DOM (it's not thread-safe)
  • The window object
  • The document object
  • The parent object
  • will not run locally (e.g. from file://)

Service Workers

  • Give developers the moving parts to solve their problems
  • Alow to create own caching patterns
  • Can only be used over HTTPS (excluding localhost)
  • Hijack connections
  • Fabricate, and filter responses

Can I use Service Workers

Can I use

Is Service Worker ready

Is Service Worker ready

Service Worker Life Cycle

Image from Google Web Fundamentals

Service Worker Registeration

 if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js')
     .then(function(registration) {
       // Registration was successful 
       console.log('Registration successful with scope:', registration.scope);
      }).catch(function(err) {
       // Registration failed 
      console.log('ServiceWorker registration failed:', err);
    });
}

Code from Google Web Fundamentals

Service Worker Installation

 self.addEventListener('install', function(event) {
// Perform install steps
});

Code from Google Web Fundamentals

Caching Static Files

 self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('mysite-static-v3').then(function(cache) {
      return cache.addAll([
        '/css/whatever-v3.css',
        '/css/imgs/sprites-v6.png',
        '/css/fonts/whatever-v8.woff',
        '/js/all-min-v4.js'
        // etc
      ]);
    })
  );
});

Code from Google Web Fundamentals

Caching Static Files

Image from Jake Archibald`s offline cookbook

Fetching Static Files

 self.addEventListener('fetch', function(event) {
    event.respondWith(
      caches.open('mysite-static-v3').then(function(cache) {
        cache.match(event.request)
           .then(function(response) {
              return response || fetch(event.request)           
          })
       );                   
    });
});

Code based on Jake Archibald`s offline cookbook

Cache First

Image from Jake Archibald`s offline cookbook

Caching On Network Response

 self.addEventListener('fetch', function(event) {
   event.respondWith(
       caches.open('mysite-dynamic').then(function(cache) {
          return cache.match(event.request).then(function (response) {
             return response || fetch(event.request).then(function(response) {
                  cache.put(event.request, response.clone());
                  return response;
                });
            });
        })
    );
});

Code from Google Web Fundamentals

Network first

Image from Jake Archibald`s offline cookbook

Cache First

Image from Jake Archibald`s offline cookbook

Race Cache and Network

Image from Jake Archibald`s offline cookbook

Cache only

Image from Jake Archibald`s offline cookbook

Network only

Image from Jake Archibald`s offline cookbook

Caching strategies

Now lets talk about...
...data storage

Cookies

  • Widely supported
  • Synchronous
  • Size limit: 4KB
  • Strings only
  • lives in document object -> inaccessible for service worker
  • Cleared very often

HTML5 Storage

Local/Session storage

  • Widely supported
  • Synchronous
  • Size limit : 2,5 ~5 MB
  • Strings only
  • Unstructured data
  • lives in document object -> inaccessible for service worker

WebSQL

  • Asynchronous
  • Size limit : 2,5 ~5 MB
  • Strings only
  • Pre defined schema
  • Quick search
  • Deprecated

IndexedDB

  • Asynchronous (event-based)
  • Size limit : 10~20% of avaiable space
  • Supported by Service Workers
  • Complex Data Objects, Indexes, transactions, cursors
  • "Worst API ever design in a history of computer science" Jake Archibald at Building offline-first PWA - Google I/O 2016
  • Promise based wrappers localForage, idb, PouchDB

File system /File API.

Notification

Engaging

  • Web Push Protocol
  • Service Workers

How does it work?

How does it work?

How does it work?

Subscribe

 navigator.serviceWorker.register('sw.js')
     .then(function(swReg){               
	        swRegistration.pushManager.subscribe({
                          userVisibleOnly: true, 
                          applicationServerKey: PUBLIC_KEY})
     .then(function(subscription){                   	
		        console.log('User successfully subscribed');          
		        fetch('/registerSubscription', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                subscription: SUBSCRIPTION_OBJ,
             })
       });          

Subscribtion object

Showing notification

 self.addEventListener('push', function(event) {
    var  data = event.data.json();
    event.waitUntil(   
       self.registration.showNotification(data.title, {
         body: data.body,
         icon: data.icon,
         vibrate: data.vibrate,
         actions: data.actions,
         requireInteraction: data.requireInteraction
      })
   );
});

Notification schema

Notification types

Demo

Demo was created by Mietek Suska and Mathias Kegelmann

PWA tools

Chrome Dev Tools

Application tab

Chrome Dev Tools

Chrome Dev Tools

Chrome Dev Tools

Chrome Dev Tools

Lighthouse

  • Chrome plugin or cmd line tool
  • Perform static as well as runtime analyze
  • Check best practices Performance and Accessiblity related to Progressive Web Apps

Lighthouse

Lighthouse

Lighthouse

SW-toolbox

Github

  • A collection of service worker tools for offlining runtime requests
  • runtime tool
  • Provides predefined cache strategies
  • Allows adding new cache strategies

SW-toolbox

                              
toolbox.router.get('/news', toolbox.networkFirst, {
    cache: {
        name: 'news'
    }
});               
 toolbox.router.get('/(google*)', global.toolbox.cacheFirst, {
    cache: {
      name: 'googleapis',
      maxEntries: 10,
      maxAgeSeconds: 86400
    },
    origin: /\.googleapis\.com$/
  });      

SW-precache

Github

  • generates service worker code that will precache specific resources so they work offline.
  • buildtime tool
  • makes managing PWA cache easier
  • integrates with sw-toolbox

SW-precache

 workboxSW.precache([
  {
    "url": "/rev/js/app-dbf8692027.js",
    "revision": "dbf8692027bc45c0716e99ce79b5c37f"
  },
  ...
  {
    "url": "/images/icon.png",
    "revision": "a10e1fffc6618c914c42a754f3e713af"
  },
  {
    "url": "/app-shell",
    "revision": "2b927fa96213157612381879d94baf6a"
  }
]);

New kind on the block - Workbox

  • The next version of sw-precache & sw-toolbox
  • Focus on modularity - smaller, standalone modules
  • Cross-browser compatible
  • Easy to integrate in build process + cli available

Workbox modules

  • workbox-broadcast-cache-update
  • workbox-cache-expiration
  • workbox-routing
  • workbox-runtime-caching
  • workbox-google-analytics

and many more tools like

PRPL pattern

  • PUSH - critical resources for the initial URL route
  • RENDER - only initial route
  • PRE-CACHE - remaining routes
  • LAZY-LOAD - and create remaining routes on demand

Hacker News PWA

  • A spiritual successor to TodoMVC
  • Each implementation is a complete Progressive Web App
  • Different frameworks
  • Different performance patterns and tools

Routes splitting

Server side

  • Server side rendering? Uncanny valley vs. SEO
  • Avoid setting TTL/ETag headers to cache service worker!
  • And double check your hosting service defaults :P