Vue.js

 PWA -> PRA

#vueconf2017 / Blake Newman / @blakenewman

slides.com/blakenewman

Caching

Offline support

Push Notifications

Code splitting

Accessibility

SSR

Browser prompt to install
​to homescreen

Less content to download

Increased engagement

Increased conversions

Announcing:

Vue.js PWA Template

Version hashes for long-term caching

Bundle size anyalitics

JS chunks pre-loaded or pre-fetched

code-splitting with dynamic import

Service worker for offline caching

Installing

  
  $ npm install -g vue-cli
  $ vue init pwa my-project
  $ cd my-project
  $ npm install
  $ npm run dev

Service Workers

Web Workers

Server

Service Worker

Cache

Client

WebSockets

WebSocket

Server

Client

Combined

Server

Service Worker

Client

WebSocket

WTF?!?

HELP

Client to server messaging system

Server

Service Worker

Cache

Client

WebSocket

Server

Service Worker

Cache

Client

WebSocket

    
    self.addEventListener('fetch', event => {
      const { request } = event;
      const url = new URL(request.url);
    
      // Ignore not GET request or is is different origin.
      if (request.method !== 'GET' || url.origin !== self.location.origin) return;
    
      event.respondWith(async () => {
        try {
          // If not online and cache available then use cache
          if (!navigator.onLine) {
            const cache = await caches.match(request);
            if (cache) return cache;
          }
    
          // Request message
          const response = await self.fetch(request);
          
          // If not 'ok' then do not cache
          if (!response.ok) return response;
    
          // Add response to cache
          const openCache = await caches.open(CACHE_NAME);
          await openCache.put(request, response.clone());
    
          return response;
        } catch (error) {
          // User is landing on a page.
          return request.mode === 'navigate' ? caches.match('./') : '';
        }
      });
    });

Server

Service Worker

Cache

Client

WebSocket

    
    const socketIO = require('socket.io');
    const express = require('express');
    
    const app = express();
    const io = socketIO(app);
    

    app.post('/api/user', () => {
      io.emit('USER_COUNT_UPDATED');
    });

    
    app.get('/api/user/count', (req, res) => {
      res.json({ count: 99283374 }).end();
    });

    

Server

Service Worker

Cache

Client

WebSocket

    
    import io from 'socket.io-client';
    
    export default store => {
      const socket = io.connect();
    
      socket.on('connect', () => store.dispatch('app/connect'));
      socket.on('disconnect', () => store.dispatch('app/disconnect'));
    
      socket.on('USER_COUNT_UPDATED', () => store.dispatch('user/getCount'));
    };

    // Load Socket layer asynchronously in separate chunk
    import('./socket').then(socket => socket.default(store));
    
    // Setup service worker
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('service-worker.js', { scope: './' });
    }

Server

Service Worker

Cache

Client

WebSocket

Twitter: @blakenewman

Github: @blake-newman

 

Feedback: https://goo.gl/LZddco

Slides: slides.com/blakenewman

Made with Slides.com