49
Offline-First The painless way

Offline first, the painless way

Embed Size (px)

Citation preview

Page 1: Offline first, the painless way

Offline-FirstThe painless way

Page 2: Offline first, the painless way

Who is this guy?

Marcel Kalveram

I Work at Hanno

I am from germany I Live in Valencia / Spain javaScript’ing since around 2008Remote UX Team we work with startups social business

hanno.co @wearehanno

@marcelkalveram

Page 3: Offline first, the painless way

Do we really need offline-first?

Traveling Commuting

Roaming Internet outage saturated network

Page 4: Offline first, the painless way
Page 5: Offline first, the painless way

What does offline-first mean?

To manage data in an app in such a way that we don't need server access in order to

do any kind of operationsome well-considered

s

Page 6: Offline first, the painless way

What is this talk about?

Native apps

Web sites

Web apps

Look stuff upDo stuff

Page 7: Offline first, the painless way

When does it make sense?

content-heavy sites(Native apps)

single page web appsstatic sites

real-time apps

self-contained appsnot our business

Page 8: Offline first, the painless way

What are the benefits?

No data-loss for the user

Offline-first apps are faster…

apps are usable all the time

Page 9: Offline first, the painless way

HOWto do offline-first…?

Page 10: Offline first, the painless way

Offline challenges

caching dynamic assetsCaching static assets

Prepare UI for offline state

Page 11: Offline first, the painless way

xhr, remote api calls .json, .xml, .csv xhr, remote api calls

Caching mechanisms

static data dynamic datapage assets

.html, .css, .jpg, .js, .ttfpage assets

browser cacheservice workers

app cache

vs.

indexedDBwebSqlweb storage

Page 12: Offline first, the painless way

browser cacheservice workers

app cache

Caching mechanisms

can’t trust him-

lack of browser support-

static data

page assets .html, .css, .jpg, .js, .ttf

page assets

Page 13: Offline first, the painless way

indexedDBwebSqlweb storage

Caching mechanisms

localforagepouchDB}lack of browser support -

api is overly complex -

dynamic dataxhr, remote api calls .json, .xml, .csv xhr, remote api calls

Page 14: Offline first, the painless way

Challenge #1Caching static assets

Page 15: Offline first, the painless way

App cache

app cacheintercepts http request

manifest file

<html manifest="my.appcache">cache, network and fallback user

browserreturns cached data

server

Page 16: Offline first, the painless way

server

App cache

cache, network and fallback

resources can be used offline.

online whitelist substitute non- cached resources

app cache

user

browser

Page 17: Offline first, the painless way

app.js image.png font.ttf

Manifestr

js

*

cache

network

fallback-

Page 18: Offline first, the painless way

App cache gotchas

1. files always come from the cache

server side generated websitessingle page applications

2. only updates if manifest file change3. need to swap the cache manually

serverapp cache

user

browserapplicationCache.swapCache();

Page 19: Offline first, the painless way

Browser support for… appcache

10+ 4+ 3.5+4+ 2.1+ 3.2+

Page 20: Offline first, the painless way

Browser support for… service workers

n/a n/a n/a40+ n/a n/a

Page 21: Offline first, the painless way

Challenge #2caching dynamic assets

Page 22: Offline first, the painless way

Caching mechanisms

dynamic dataxhr, remote api calls .json, .xml, .csv xhr, remote api calls

indexedDBwebSqlweb storage

localforagepouchDB}lack of browser support -

api is overly complex -

Page 23: Offline first, the painless way

Using web storage

no online connection required

session storage or local storagekey/value store

app cachestorage

user

browser

Page 24: Offline first, the painless way

Using web storage APIs

currentHighscorelastMove

levelsCompleted

1890D4E512

keys values

Page 25: Offline first, the painless way

Using web storage APIs

localStorage.setItem("lastMove", "D4E5");localStorage.getItem("levelsCompleted");

currentHighscorelastMove

levelsCompleted

1890D4E512

Page 26: Offline first, the painless way

Browser support for… localstorage

8+ 3.5+ 4+4+ 2.1+ 3.2+

Page 27: Offline first, the painless way

asynchronous

Why don’t we just use…indexedDB?

web storage indexedDB

synchronouslimited to strings supports large data sets

no indexes indexes10mb storage 50mb storage

Page 28: Offline first, the painless way

Browser support for… indexedDB?

*Subfeatures not supported**buggy behavior in iOS8

10+ 10+ 7.1+23+ 4.4+ 8+* **

Page 29: Offline first, the painless way

Browser support for… webSQL?

*is no longer being maintained

*

n/a n/a 3.1+4+ 2.1+ 3.2+

Page 30: Offline first, the painless way

browser APIs…

localStorage

webSql

indexedDB

limited storage optionslack of browser supportoverly complex api

Page 31: Offline first, the painless way

localForage…

…limitations of localStorage

helps us overcome

…browser differencessupports all js objects

asynchronousindexedDB, webSQL and localstorage

loads best driver for us

Page 32: Offline first, the painless way

jsoncurrentHighscore

lastMovelevelsCompleted

1890

12

localForage

localForage.setItem("lastMove", incrediblyComplexJsonObject)localForage.getItem("levelsCompleted", function(err, val) {…});

takes care of

(de-)serialization

.then(…)

supports promises

Page 33: Offline first, the painless way

https://github.com/mozilla/localForage

Page 34: Offline first, the painless way

What about syncing?

localstorageindexedDB

localforage

our responsibility

Page 35: Offline first, the painless way

What about syncing?

localstorageindexedDB

localforage

pouchDB

our responsibility

Page 36: Offline first, the painless way

object

pouchDB API

pdb.put(o, cb) pdb.get(id, cb)currentHighscore

lastMovelevelsCompleted

1890

12_id: "lastMove", lastPos: "D4" newPos: "E5"

"lastMove"

Page 37: Offline first, the painless way

pouchDB sync

pdb.sync(remoteDB);

new PouchDB("http://localhost:5984/myremotedb")

Page 38: Offline first, the painless way

https://github.com/pouchdb/pouchdb

Page 39: Offline first, the painless way

Challenge #3preparing our ui

Page 40: Offline first, the painless way

yes

no

no

yes

am i online…

do i have updates…

sync with server

offline app

store locally

Page 41: Offline first, the painless way

How to detect online status

1navigator

events

2appcache events

3xhr

events

Page 42: Offline first, the painless way

Navigator events

window.addEventListener("online", function(e) {alert("online");})

online/offline

navigator.onLine

true/false

Page 43: Offline first, the painless way

Navigator events

is always onlineworks only in offline-modeshows online even if

connection is unreliable

Page 44: Offline first, the painless way

Appcache events

applicationCache.addEventListener("error", function(e) { … });

checking progress cached

error

Page 45: Offline first, the painless way

XHR events

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(e) {

}

if (xhr.status != 200) {

}there is probably a connection issue

Page 46: Offline first, the painless way

https://github.com/HubSpot/offline

Page 47: Offline first, the painless way

static and dynamic datawith remote server

what to take offlineif offline-first makes sense

use eventsprepare ui for flawless user experience

considerdecide

to detect offline state

cachesync

Page 48: Offline first, the painless way

with your userssome good in the world

empathize Do

Page 49: Offline first, the painless way

Thanks!

hanno.co