WarsawJS Meetup: Offline-first applications

We talk about JavaScript. Each month in Warsaw, Poland.

Speaker

Andriy Mykulyak

"Offline-first applications"

2018-10-10

@amykulyak

Who am I ?

Senior software consultant

@ Shedul, Warsaw

Full stack developer. Like challenges, JavaScript, Python and Elixir.
Privately is passionate about triathlon.

"Do. Or do not. There is no try" (c) Yoda

Plan

  1. What is offline-first application ?
  2. Offline-first architecture
  3. Static asset caching
  4. What is with application data ?
  5. Adapting UI to offline
  6. Collaborative applications
  7. Other stuff

What is offline-first application ?

An application that remains functional even without network connection.

Also usable in cases:

Offline - dinosaurs

Offline - basic

Offline - readable

Offline - first

Offline - omg

Architecture - SPA

Offline architecture

Write applications as if there were no network connection at all.

Consider communication with server as a side effect.

Why not native apps ?

Offline challenges

Service workers to the rescue !

Architecture - how SW works

Architecture - service worker lifecycle

Service worker registration

      
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    // service worker will control
    // everything under /scope path
    navigator.serviceWorker.register('/scope/sw.js');
  });
}
      
    

Service worker lifecycle events

      
self.addEventListener('install', (event) => {
  // we'll install soon
});

self.addEventListener('activate', (event) => {
  // no other service workers are present
  // we'll control our pages soon :)
});
      
    

Architecture - offline-first application

Asset caching

Workbox

Workbox setup - easy way

      
import workboxPlugin from 'workbox-webpack-plugin';
export default {
  plugins: [
    new workboxPlugin.GenerateSW(options),
  ],
};
      
    

Workbox setup - customizable

      
import workbox from 'workbox-webpack-plugin';
export default {
  plugins: [
    new workbox.InjectManifest({
      swSrc: '/scope/service-worker.js'
    })
  ]
}
      
    

Caching strategies

Precaching - Cache API

      
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('cache-name').then(cache => {
      cache.addAll([ ... ]); // non-required deps
      return cache.addAll([ ... ]); // required deps
    })
  )
});
      
    

Precaching with Workbox

      
        importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.2/workbox-sw.js');
        importScripts('/scope/service-worker.js');

        workbox.precaching.precacheAndRoute(
          self.__precacheManifest || []
        );
      
    

Cache, fallback to network - Cache API

      
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || global.fetch(event.request);
    })
  );
});
      
    

Cache, fallback to network - Workbox

      
workbox.routing.registerRoute(
  /\/avatars/.*\.(?:png|jpg|jpeg|svg|gif)/,
  workbox.strategies.cacheFirst({
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 20,
        maxAgeSeconds: 7 * 24 * 60 * 60,
      })
    ],
  })
);
        
    

Where to store application data ?

Using IndexedDB

IndexedDB wrappers

Application data - framework support

Application data - reading

Application data - writing

Adapting UI to offline

Collaborative work

Conflict resolution strategies

Other (interesting) stuff

Links

Time for questions

Thank you !

See you next month at WarsawJS