Live version of slide deck

https://slides.com/capouch/pwa/live

Progressive Web 

Applications

Brian Capouch

brianc@palaver.net

Danilo Zekovic

danilozeka93@gmail.com

Warning:

This is experimental technology

Game Plan:

  • Overview of basic concepts
  • A look at critical components
  • Hands-on demonstrations 

What is a PWA?

  • A website with "special sauce"
  • Goal is more "appy" user experience
    • Proxy-like capability
    • Installs to device homescreen
    • Servers can "push" notifications

The special sauce

  • It is called a service worker
  • Installs itself into the browser
  • Maintains a local resource cache
  • Intercepts web fetch requests
  • Receives push notifications

Service Worker

  • A module of JavaScript code
  • Cannot access the DOM!!
  • Runs independently of the page that installed it.
  • Responds to a variety of events

PWA Requirements

  • Must run over HTTPS
  • A manifest file is required
  • Service workers follow "lifecycle" rules
    • Activate on second visit to site

Caching

  • Service workers have dedicated, named caches
  • Caches never expire
  • They implement the three basic functions
    • Store
    • Retrieve
    • Remove

Push Notifications

  • Complex in conception and execution
  • User must explicitly allow notifications
  • Client can subscribe/unsubscribe at will
  • Client must possess VAPID key
  • Subscription is to browser, not server

Notifications, con't

  • Client must send subscription to server
  • Server does not send notification!!
    • Messaging server handles actual push
    • Messaging server "belongs" to browser
  • Subscriptions technically never expire

Push-NotifyEvent flow:

  1. User chooses to allow notifications
  2. Client, using VAPID key, requests subscription
  3. Client informs server of subscription details
  4. Site administrator invokes push-notify function
  5. Suscription, key pair, payload sent to messaging server
  6. Messaging server delivers notification to service worker
  7. Service worker logic notifies user of notification

Resource Links

Live Demo Time!!

We will show:

  • Service worker "proxy caching"
  • Generating VAPID and SSL
  • Subscribing 
  • Let's try a push notification
Service worker code to implement proxy cache - ~/public/sw.js:21

self.addEventListener('fetch', function(event) {
  console.log('SW Intercepting: ' + event.request.url);
  event.respondWith(
    caches.match(event.request).then(function(response) {
      // Cache hit - return response
      //return response || fetch(event.request);
      if (response){
        console.log("Returning cached value for: " + event.request.url);
        return response;
      }
      // No hit; fetch resource
      return fetch(event.request);
    })
  );
});
~/app/components/views/Subscribe.js:113

// Service routines to handle subscription activities
function subscribeUser() {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
  .then(function(subscription) {
    console.log('User is subscribed.');
    updateSubscriptionOnServer(subscription);
    isSubscribed = true;
  })
  .catch(function(err) {
    console.log('Failed to subscribe the user: ', err);
  });
}
Routine to send push notification: ~/server/routes.js:25

const pushOptions = {
        vapidDetails: {
          subject: 'mailto:' + vapidKeys.EMAIL,
          publicKey: vapidKeys.PUBLIC_KEY,
          privateKey: vapidKeys.PRIVATE_KEY
        },
      }

      webPush.sendNotification(
        subscription,
        payload,
        pushOptions
      )
Show the user the notification message - ~/public/sw.js:38

// Copied from https://developers.google.com/web/fundamentals/engage-and-retain/push-notifications/good-notification
self.addEventListener('push', event => {
  let thisMessage = event.data.text()
    console.log("We got this message: " + thisMessage)
    console.log('[Service Worker] Push Received.');
    console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

    const title = 'PWA';
    const options = {
      body: thisMessage,
      // We didn't implement these pieces
      icon: 'images/icon.png',
      badge: 'images/badge.png'
    };

    event.waitUntil(self.registration.showNotification(title, options));
  })