offline first, the painless way
TRANSCRIPT
Offline-FirstThe 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
Do we really need offline-first?
Traveling Commuting
Roaming Internet outage saturated network
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
What is this talk about?
Native apps
Web sites
Web apps
Look stuff upDo stuff
When does it make sense?
content-heavy sites(Native apps)
single page web appsstatic sites
real-time apps
self-contained appsnot our business
What are the benefits?
No data-loss for the user
Offline-first apps are faster…
apps are usable all the time
HOWto do offline-first…?
Offline challenges
caching dynamic assetsCaching static assets
Prepare UI for offline state
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
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
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
Challenge #1Caching static assets
App cache
app cacheintercepts http request
manifest file
<html manifest="my.appcache">cache, network and fallback user
browserreturns cached data
server
server
App cache
cache, network and fallback
resources can be used offline.
online whitelist substitute non- cached resources
app cache
user
browser
app.js image.png font.ttf
Manifestr
js
*
cache
network
fallback-
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();
Browser support for… appcache
10+ 4+ 3.5+4+ 2.1+ 3.2+
Browser support for… service workers
n/a n/a n/a40+ n/a n/a
Challenge #2caching dynamic assets
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 -
Using web storage
no online connection required
session storage or local storagekey/value store
app cachestorage
user
browser
Using web storage APIs
currentHighscorelastMove
levelsCompleted
1890D4E512
keys values
Using web storage APIs
localStorage.setItem("lastMove", "D4E5");localStorage.getItem("levelsCompleted");
currentHighscorelastMove
levelsCompleted
1890D4E512
Browser support for… localstorage
8+ 3.5+ 4+4+ 2.1+ 3.2+
asynchronous
Why don’t we just use…indexedDB?
web storage indexedDB
synchronouslimited to strings supports large data sets
no indexes indexes10mb storage 50mb storage
Browser support for… indexedDB?
*Subfeatures not supported**buggy behavior in iOS8
10+ 10+ 7.1+23+ 4.4+ 8+* **
Browser support for… webSQL?
*is no longer being maintained
*
n/a n/a 3.1+4+ 2.1+ 3.2+
browser APIs…
localStorage
webSql
indexedDB
limited storage optionslack of browser supportoverly complex api
localForage…
…limitations of localStorage
helps us overcome
…browser differencessupports all js objects
asynchronousindexedDB, webSQL and localstorage
loads best driver for us
jsoncurrentHighscore
lastMovelevelsCompleted
1890
12
localForage
localForage.setItem("lastMove", incrediblyComplexJsonObject)localForage.getItem("levelsCompleted", function(err, val) {…});
takes care of
(de-)serialization
.then(…)
supports promises
https://github.com/mozilla/localForage
What about syncing?
localstorageindexedDB
localforage
our responsibility
What about syncing?
localstorageindexedDB
localforage
pouchDB
our responsibility
object
pouchDB API
pdb.put(o, cb) pdb.get(id, cb)currentHighscore
lastMovelevelsCompleted
1890
12_id: "lastMove", lastPos: "D4" newPos: "E5"
"lastMove"
pouchDB sync
pdb.sync(remoteDB);
new PouchDB("http://localhost:5984/myremotedb")
https://github.com/pouchdb/pouchdb
Challenge #3preparing our ui
yes
no
no
yes
am i online…
do i have updates…
sync with server
offline app
store locally
How to detect online status
1navigator
events
2appcache events
3xhr
events
Navigator events
window.addEventListener("online", function(e) {alert("online");})
online/offline
navigator.onLine
true/false
Navigator events
is always onlineworks only in offline-modeshows online even if
connection is unreliable
Appcache events
applicationCache.addEventListener("error", function(e) { … });
checking progress cached
error
XHR events
var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(e) {
}
if (xhr.status != 200) {
}there is probably a connection issue
https://github.com/HubSpot/offline
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
with your userssome good in the world
empathize Do