Some statistics

Legendary Car

Minsk

Some more statistics

Legendary Library

Trends

https://trends.google.com/trends/explore?date=2013-02-09%202017-03-09&q=%2Fm%2F0268gyp,%2Fm%2F0j45p7w,%2Fm%2F012l1vxv,BackboneJS,ExtJS

Trends

https://trends.google.com/trends/explore?date=2013-02-09%202017-03-09&q=%2Fm%2F0268gyp,%2Fm%2F0j45p7w,%2Fm%2F012l1vxv,BackboneJS,ExtJS

Uruguay

EPAM CC

Customer & Offline Second

Insurance Domain

Customer's Clients

Belarus

USA

Reality

Offline

  • Avoid application crashes or errors

  • Allow users to keep working, seamlessly

  • Avoid multiple changes

  • Time Limit

Concerns

Step 0: rules

  • Focus on your goals

  • Do not refresh libraries

  • Do not touch lint or style guides 

  • Do not touch working code

  • Do not refactor anything

Rules

Step 1: detect offline

  function updateOnlineStatus(event) {
    let condition = navigator.onLine ? 'online' : 'offline';

    console.log(`Do smth. You are ${condition}`);
  }

  window.addEventListener('online',  updateOnlineStatus);

  window.addEventListener('offline', updateOnlineStatus);

Detect Status

https://jsfiddle.net/cz9u13tr/

Baidu Map

Gracefully Degrate

Gracefully Degrate

Step 2: Requests

  • $http

  • new XMLHttpRequest()

  • $.ajax ($.get, $.post, ...)

  • fetch

  • new ActiveXObject

  • ...

Requests

Request Facade

REST

$.ajax

XHR

fetch

Offline...

Facade

Step 3: Detect Slow...

Online or Offline?

  • Slow or intermittent internet

  • Slow or intermittent WiFi

  • Avoid HTTP Timeouts

Detect slow connection

Request Facade + Circuit Breaker

REST

Request

Offline...

Facade

Closed

Opened

Closed

Success

Open

Fast Failer

Open

Half-Open

Success: Open

Try one request

Fail: Close

Circuit Breaker Pattern

https://github.com/HubSpot/offline

Offline.js

https://github.com/HubSpot/offline

Offline.js

{
  reconnect: {
    // How many seconds should we wait before rechecking.
    initialDelay: 3,

    // How long should we wait between retries.
    delay: (1.5 * last delay, capped at 1 hour)
  }
}

https://github.com/HubSpot/offline

Offline.js

{
  // Should we store and attempt to remake requests
  // which fail while the connection is down.

  requests: true,
}

https://github.com/HubSpot/offline

Offline.js

// By default, Offline makes an XHR request
// to load your /favicon.ico
// You can change the URL it hits
// (respond with a quick 204 is perfect):

Offline.options = {checks: {xhr: {url: '/connection-test'}}};

Intermediate Result

  • Offline Status

  • Request

  • Slow or Intermittent Connection

Online

Online

Offline

Restart

Browser

Intermittent Offline

Step 4: Reload Page

Prevent Reload

window.onbeforeunload = function(e) {
  let dialogText = `You are offline! Don't do it!`;

  e.returnValue = dialogText;

  return dialogText;
};

https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload

Service Workers

Installation

https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/

Cache Response

https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/

Cache Storage

  • Promisified

  • Store Request/Response key/value data

  • Persistent between browser restarts

Work with Service Workers

HTTPS

HTTPS

HTTPS

<script src="http://example.com/jquery.js"></script>

<link rel="stylesheet" href="http://assets.example.com/style.css"/>

<img src="http://img.example.com/logo.png"/>;

<p>Read this nice <a href="http://example.com/2014/12/24/">
new post on cats!</a></p>

HTTPS: fix mixed content

<meta http-equiv="Content-Security-Policy"
 content="upgrade-insecure-requests">
<meta http-equiv="Content-Security-Policy"
 content="block-all-mixed-content">

Activation

https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('my-cashe-v1').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
      ]);
    })
  );
});

Installation

[
    "./48065a15ae3a16e845a528a3c0467487.svg",
    "./6beb3319398d06b0635871740330ac7b.svg",
    "./8450ddeb645c18bff7890bccc95881a7.svg",
    "./ba17b770588f23af1184e66179dc222d.svg",
    "./2e030a00362fe30a27bc0750b0626797.svg",
    "./3585e1891683a708eabb7ed43446cf82.svg",
    "./main.e5d23aa4f5b56b06e5ec.bundle.js",
    "./1.e5d23aa4f5b56b06e5ec.chunk.js",
    "./main.e5d23aa4f5b56b06e5ec.css",
    "./1.e5d23aa4f5b56b06e5ec.chunk.js.gz",
    "./1.e5d23aa4f5b56b06e5ec.bundle.map.gz",
    "./main.e5d23aa4f5b56b06e5ec.css.gz",
    "./main.e5d23aa4f5b56b06e5ec.bundle.js.gz"
]

Assets Installation

https://github.com/GoogleChrome/sw-precache

https://github.com/GoogleChrome/sw-toolbox

Service Worker Libraries:

  • sw-precashe

  • sw-toolbox

https://github.com/GoogleChrome/sw-toolbox

Service Worker Library: sw-toolbox

toolbox.router.get(/urlPattern/, handler, options);

Matches requests using the GET, POST, PUT, DELETE or HEAD HTTP methods respectively.

https://jakearchibald.com/2014/offline-cookbook/

Network Strategies === handlers

https://jakearchibald.com/2014/offline-cookbook/

Network Strategy: Cache Only

https://jakearchibald.com/2014/offline-cookbook/

Network Strategy: Cache Only

class CustomHandler extends workbox.runtimeCaching.Handler {
  handle({ event }) {
    console.log('CustomHandler is handling', event);
  }
}

Network Strategy: Cache & Network race

https://jakearchibald.com/2014/offline-cookbook/

Network Strategy: Network first

https://jakearchibald.com/2014/offline-cookbook/

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('mycashe-v1').then(function(cache) {

      cache.addAll(
        // large and unimportant resources
      );

      return cache.addAll(
        // important resources
      );

    })
  );
});

Custom Logic

https://github.com/NekR/offline-plugin

+ AppCache

+ Manifest

SW Libraries: Webpack Offline Plugin

Intermediate Result

  • Offline Status

  • Request

  • Slow or Intermittent Connection

  • Cache Resources

Step 5: Storages

Storage Size

30-40 Mb

~

  • Limited to 5 MBs

  • Store only Strings

  • Persistent between browser restarts

Local Storage

Web SQL

  • More complex than localStorage

  • 50 MB + (calculate on quota)

  • Stores Objects, Strings and other

  • Async

 

IndexedDB

https://nolanlawson.com/2015/09/29/indexeddb-websql-localstorage-what-blocks-the-dom/

Speed Tests: insert 1k objects

https://nolanlawson.com/2015/09/29/indexeddb-websql-localstorage-what-blocks-the-dom/

Speed Tests: insert 1m objects

https://nolanlawson.github.io/html5workertest/

Storages Support in Service Workers

Pull Stategy

Rest API

Data

IndDB

UI-Page

Data

Size/Diff

Cache

Load

Data

40 Mb/...

Pull Strategy

Intermediate Result

  • Offline Status

  • Request

  • Slow or Intermittent Connection

  • Cache Resources

  • Persistence data

Business Logic?

Step 6: Isomorphism

Client App

Server App

Request Facade

Servises

Rest API

IndDB

Mongo

Isomorphism

Router

Adapter

Driver

Mongo API Everywhere

IndDB

Mongo

Router

Adapter

Driver

Servises

IndDB

Mongo

Mongo API Everywhere

Mongo

Adapter API

Driver API

Step 7: Adapters

6393

https://github.com/louischatriot/nedb

  • Basic Querying

  • Operators ($lt, $lte, $gt, $gte, $in, $nin, $ne, $exists, $regex)

  • Logical operators $or, $and, $not, $where

  • Sorting and paginating

  • Projections

  • Indexing

  • File Persistance

3290

http://lokijs.org/#/

  • Fast Performance!

  • Indexing / Secondary Indexing / Unique Indexing

  • Persistence IndexedDB Adapter

  • Partial compatibility with MongoDB API

578

https://github.com/mWater/minimongo

Push Strategy?

Push Strategy

Rest API

ClientDB

UI-Page

Data

Update

Delete

Data

Data

https://pouchdb.com/

  • Omniusable on browsers, nodejs, election, cordova, react-native and every other javascript-runtime

  • Replication between client and server-data, compatible with PouchDB, CouchDB and IBM Cloudant

  • Mango-Query exactly like you know from mongoDB and mongoose

https://github.com/pubkey/rxdb

https://www.meteor.com/

https://www.rethinkdb.com/

Horizon is a realtime, open-source backend for JavaScript apps

https://horizon.io/

What else?

https://loopback.io/

https://github.com/gritzko/swarm

And what is the result?

Final Result

  • Offline Status

  • Request

  • Slow or Intermittent Connection

  • Cache Resources

  • Persistence data

  • Business Logic

  • Partial Sync

Result for Insurance Company

  • Offline Support

  • 1 month of development

  • Up to 5% profit

Thank you!

Questions?

Offline Second

By Aliaksei Bahachuk

Offline Second

Nowadays, there are many tips how start your project following the "Offline First" principle. But how add a support offline mode for applications that have already been released? What tactics and architectural approaches are used? What technologies and libraries are looking for? What storages are needed for implementation of pull/push strategies?

  • 1,279