Offline strategies for HTML5 web applications - ConFoo13

94
Offline strategies for HTML5 web applications Stephan Hochdörfer, bitExpert AG

Transcript of Offline strategies for HTML5 web applications - ConFoo13

Page 1: Offline strategies for HTML5 web applications - ConFoo13

Offline strategies for HTML5 web applicationsStephan Hochdörfer, bitExpert AG

Page 2: Offline strategies for HTML5 web applications - ConFoo13

Offline strategies for HTML5 web applications

About me

Stephan Hochdörfer

Head of IT at bitExpert AG, Germany

enjoying PHP since 1999

[email protected]

@shochdoerfer

Page 3: Offline strategies for HTML5 web applications - ConFoo13
Page 4: Offline strategies for HTML5 web applications - ConFoo13
Page 5: Offline strategies for HTML5 web applications - ConFoo13
Page 6: Offline strategies for HTML5 web applications - ConFoo13
Page 7: Offline strategies for HTML5 web applications - ConFoo13
Page 8: Offline strategies for HTML5 web applications - ConFoo13
Page 9: Offline strategies for HTML5 web applications - ConFoo13
Page 10: Offline strategies for HTML5 web applications - ConFoo13
Page 11: Offline strategies for HTML5 web applications - ConFoo13

Offline strategies for HTML5 web applications

[...] we take the next step, announcing 2014 as the target for

Recommendation.Jeff Jaffe, Chief Executive Officer, World Wide Web Consortium

Page 12: Offline strategies for HTML5 web applications - ConFoo13
Page 13: Offline strategies for HTML5 web applications - ConFoo13

What does „offline“ mean?

Offline strategies for HTML5 web applications

Page 14: Offline strategies for HTML5 web applications - ConFoo13

What does „offline“ mean?

Offline strategies for HTML5 web applications

Application vs. Content

Page 15: Offline strategies for HTML5 web applications - ConFoo13

What does „offline“ mean?

Offline strategies for HTML5 web applications

Application Cache vs. Offline Storage

Page 16: Offline strategies for HTML5 web applications - ConFoo13

App Cache for caching static resources

Offline strategies for HTML5 web applications

<!DOCTYPE html><html lang="en">

HTML Page:

Page 17: Offline strategies for HTML5 web applications - ConFoo13

CACHE MANIFEST

js/app.jscss/app.cssfavicon.icohttp://someotherdomain.com/image.png

<!DOCTYPE html><html lang="en" manifest="cache.manifest">

App Cache for caching static resources

Offline strategies for HTML5 web applications

HTML Page:

cache.manifest (served with Content-Type: text/cache-manifest):

Page 18: Offline strategies for HTML5 web applications - ConFoo13

CACHE MANIFEST# 2012­09­16

NETWORK:data.php

CACHE:/main/home/main/app.js/settings/home/settings/app.jshttp://myhost/logo.pnghttp://myhost/check.pnghttp://myhost/cross.png

App Cache for caching static resources

Offline strategies for HTML5 web applications

Page 19: Offline strategies for HTML5 web applications - ConFoo13

CACHE MANIFEST# 2012­09­16

FALLBACK:/ /offline.html

NETWORK:*

App Cache for caching static resources

Offline strategies for HTML5 web applications

Page 20: Offline strategies for HTML5 web applications - ConFoo13

// events fired by window.applicationCachewindow.applicationCache.onchecking = function(e) {log("Checking for updates");}window.applicationCache.onnoupdate = function(e) {log("No updates");}window.applicationCache.onupdateready = function(e) {log("Update ready");}window.applicationCache.onobsolete = function(e) {log("Obsolete");}window.applicationCache.ondownloading = function(e) {log("Downloading");}window.applicationCache.oncached = function(e) {log("Cached");}window.applicationCache.onerror = function(e) {log("Error");}

// Log each filewindow.applicationCache.onprogress = function(e) {  log("Progress: downloaded file " + counter);  counter++;};

App Cache Scripting

Offline strategies for HTML5 web applications

Page 21: Offline strategies for HTML5 web applications - ConFoo13

// Check if a new cache is available on page load.window.addEventListener('load', function(e) {  window.applicationCache.addEventListener('updateready',  function(e) {

    if(window.applicationCache.status ==         window.applicationCache.UPDATEREADY) {      // Browser downloaded a new app cache.      // Swap it in and reload the page      window.applicationCache.swapCache();      if (confirm('New version is available. Load it?)) {        window.location.reload();      }    } else {      // Manifest didn't change...    }  }, false);

}, false);

App Cache Scripting

Offline strategies for HTML5 web applications

Page 22: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

Page 23: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

1. Files are always(!) served from the application cache.

Page 24: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

2. The application cache only updates if the content of the manifest itself

has changed!

Page 25: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

3. If any of the files listed in the CACHE section can't be retrieved, the

entire cache will be disregarded.

Page 26: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

4. If the manifest file itself can't be retrieved, the cache will ignored!

Page 27: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

5. Non-cached resources will not load on a cached page!

Page 28: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

6. The page needs to be reloaded, otherwise the new resources do not

show up!

Page 29: Offline strategies for HTML5 web applications - ConFoo13

App Cache – Some gotchas!

Offline strategies for HTML5 web applications

7. To avoid the risk of caching manifest files set expires headers!

Page 30: Offline strategies for HTML5 web applications - ConFoo13

App Cache – What to cache?

Offline strategies for HTML5 web applications

Yes: Fonts Splash image App icon Entry page Fallback bootstrap

No: CSS HTML Javascript

Page 31: Offline strategies for HTML5 web applications - ConFoo13

App Cache – What to cache?

Offline strategies for HTML5 web applications

Use the App Cache only for „static content“.

Page 32: Offline strategies for HTML5 web applications - ConFoo13

The Data URI scheme

Offline strategies for HTML5 web applications

Page 33: Offline strategies for HTML5 web applications - ConFoo13

<!DOCTYPE HTML><html> <head>  <title>The Data URI scheme</title>  <style type="text/css">  ul.checklist li {    margin­left: 20px;    background: white url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==') no­repeat scroll left top;}  </style> </head> <body>  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot"> </body></html>

The Data URI scheme

Offline strategies for HTML5 web applications

Page 34: Offline strategies for HTML5 web applications - ConFoo13

Storing dynamic data locally (in HTML5)

Offline strategies for HTML5 web applications

Page 35: Offline strategies for HTML5 web applications - ConFoo13
Page 36: Offline strategies for HTML5 web applications - ConFoo13

Storing dynamic data locally (in HTML5)

Offline strategies for HTML5 web applications

Find the sources here:github.com/bitExpert/html5-offline

Page 37: Offline strategies for HTML5 web applications - ConFoo13

Storing dynamic data locally (in HTML5)

Offline strategies for HTML5 web applications

Web Storage, Web SQL Database, IndexedDB, File API

Page 38: Offline strategies for HTML5 web applications - ConFoo13

Web Storage

Offline strategies for HTML5 web applications

Page 39: Offline strategies for HTML5 web applications - ConFoo13

Web Storage

Offline strategies for HTML5 web applications

Very convenient form of offline storage: simple key-value store

Page 40: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: 2 different types

Offline strategies for HTML5 web applications

localStorage vs. sessionStorage

Page 41: Offline strategies for HTML5 web applications - ConFoo13

function add(item) {try {

// for a new item set idif((typeof item.id === "undefined") 

             || (null == item.id) || ("" == item.id)) {item.id = get_lastIndex() + 1;

}

// store object as stringlocalStorage.setItem(item.id, 

             JSON.stringify(item)         );

// update the indexset_lastIndex(item.id);

}catch(ex) {

console.log(ex);}

}

Web Storage: Add item

Offline strategies for HTML5 web applications

Page 42: Offline strategies for HTML5 web applications - ConFoo13

function modify(item) {try {

// store object as stringlocalStorage.setItem(item.id, 

             JSON.stringify(item)         );

}catch(ex) {

console.log(ex);}

}

Web Storage: Modify item

Offline strategies for HTML5 web applications

Page 43: Offline strategies for HTML5 web applications - ConFoo13

function remove (id) {try {

localStorage.removeItem(id);}catch(ex) {

console.log(ex);}

}

Web Storage: Remove item

Offline strategies for HTML5 web applications

Page 44: Offline strategies for HTML5 web applications - ConFoo13

function read() {      try {

      var lastIdx = get_lastIndex();      for(var i = 1; i <= lastIdx; i++) {

      if(null !== localStorage.getItem(i)) {      // parse and render item      var item = JSON.parse(

                        localStorage.getItem(i)                   );

      }      }

      }      catch(ex) {

      console.log(ex);      }}

Web Storage: Read items

Offline strategies for HTML5 web applications

Page 45: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: What about sessionStorage?

Offline strategies for HTML5 web applications

Page 46: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: What about sessionStorage?

Offline strategies for HTML5 web applications

Replace „localStorage „with „sessionStorage“

Page 47: Offline strategies for HTML5 web applications - ConFoo13

function add(item) {try {

// for a new item set idif((typeof item.id === "undefined") 

             || (null == item.id) || ("" == item.id)) {item.id = get_lastIndex() + 1;

}

// store object as stringsessionStorage.setItem(item.id, 

             JSON.stringify(item)         );

// update the indexset_lastIndex(item.id);

}catch(ex) {

console.log(ex);}

}

Web Storage: Add item to sessionStorage

Offline strategies for HTML5 web applications

Page 48: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Don`t like method calls?

Offline strategies for HTML5 web applications

var value = "my value";

// method calllocalStorage.setItem("key", value);

// Array accessorlocalStorage[key] = value;

// Property accessorlocalStorage.key = value;

Page 49: Offline strategies for HTML5 web applications - ConFoo13
Page 50: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Pro

Offline strategies for HTML5 web applications

Most compatible format up to now.

Page 51: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Con

Offline strategies for HTML5 web applications

The data is not structured.

Page 52: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Con

Offline strategies for HTML5 web applications

No transaction support!

Page 53: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Con

Offline strategies for HTML5 web applications

Lack of automatically expiring storage.

Page 54: Offline strategies for HTML5 web applications - ConFoo13

Web Storage: Con

Offline strategies for HTML5 web applications

Inadequate information about storage quota.

Page 55: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database

Offline strategies for HTML5 web applications

Page 56: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database

Offline strategies for HTML5 web applications

An offline SQL database based on SQLite, an general-purpose SQL engine.

Page 57: Offline strategies for HTML5 web applications - ConFoo13

var onError = function(tx, ex) {alert("Error: " + ex.message);

};

var onSuccess = function(tx, results) {var len = results.rows.length;

for(var i = 0; i < len; i++) {// render found todo itemrender(results.rows.item(i));

}};

Web SQL Database: Callback methods

Offline strategies for HTML5 web applications

Page 58: Offline strategies for HTML5 web applications - ConFoo13

// initalize the database connectionvar db = openDatabase('todo', '1.0', 'Todo Database',    5 * 1024 * 1024 );

db.transaction(function (tx) {tx.executeSql(

'CREATE TABLE IF NOT EXISTS todo '+          '(id INTEGER PRIMARY KEY ASC, todo TEXT)',

[],          onSuccess,          onError

);});

Web SQL Database: Setup Database

Offline strategies for HTML5 web applications

Page 59: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Add item

Offline strategies for HTML5 web applications

function add(item) {db.transaction(function(tx) {

tx.executeSql('INSERT INTO todo (todo) VALUES (?)',[

item.todo],onSuccess,onError

);});

}

Page 60: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Modify item

Offline strategies for HTML5 web applications

function modify(item) {db.transaction(function(tx) {

tx.executeSql('UPDATE todo SET todo = ? WHERE id = ?',[

item.todoitem.id

],onSuccess,onError

);});

}

Page 61: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Remove item

Offline strategies for HTML5 web applications

function remove(id) {db.transaction(function (tx) {

tx.executeSql('DELETE FROM todo WHERE id = ?',[

id],onSuccess,onError

);});

}

Page 62: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Read items

Offline strategies for HTML5 web applications

function read() {db.transaction(function (tx) {

tx.executeSql('SELECT * FROM todo',[],onSuccess,onError

);});

}

Page 63: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Pro

Offline strategies for HTML5 web applications

It`s a SQL database within the browser!

Page 64: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Con

Offline strategies for HTML5 web applications

It`s a SQL database within the browser!

Page 65: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Con

Offline strategies for HTML5 web applications

SQLite is slooooow!

Page 66: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database: Con

Offline strategies for HTML5 web applications

The specification is no longer part of HTML5!

Page 67: Offline strategies for HTML5 web applications - ConFoo13

IndexedDB

Offline strategies for HTML5 web applications

Page 68: Offline strategies for HTML5 web applications - ConFoo13

IndexedDB

Offline strategies for HTML5 web applications

A nice compromise between Web Storage and Web SQL Database giving

you the best of both worlds.

Page 69: Offline strategies for HTML5 web applications - ConFoo13

Web SQL Database vs. IndexedDB

Offline strategies for HTML5 web applications

Category Web SQL IndexedDB

Location Tables contain columns and rows

objectStore contains Javascript objects and keys

Query Mechanism

SQL Cursor APIs, Key Range APIs, and Application Code

Transaction Lock can happen on databases, tables, or rows on READ_WRITE transactions

Lock can happen on database VERSION_CHANGE transaction, on an objectStore READ_ONLY and READ_WRITE transactions.

Transaction Commits

Transaction creation is explicit. Default is to rollback unless we call commit.

Transaction creation is explicit. Default is to commit unless we call abort or there is an error that is not caught.

Page 70: Offline strategies for HTML5 web applications - ConFoo13

// different browsers, different naming conventionsvar indexedDB = window.indexedDB ||    window.webkitIndexedDB || window.mozIndexedDB ||    window.msIndexedDB;

var IDBTransaction = window.IDBTransaction ||   window.webkitIDBTransaction;

var IDBKeyRange = window.IDBKeyRange ||    window.webkitIDBKeyRange;

IndexedDB: Preparation

Offline strategies for HTML5 web applications

Page 71: Offline strategies for HTML5 web applications - ConFoo13

var db = null;var request = indexedDB.open("todo");request.onfailure = onError;request.onsuccess = function(e) {

db = request.result;var v = "1.0";if(v != db.version) {

var verRequest = db.setVersion(v);verRequest.onfailure = onError;verRequest.onsuccess = function(e) {

var store = db.createObjectStore("todo",{

keyPath: "id",autoIncrement: true

});e.target.transaction.oncomplete = 

                function() {};};

}};

IndexedDB: Create object store

Offline strategies for HTML5 web applications

Page 72: Offline strategies for HTML5 web applications - ConFoo13

function add(item) {try {

var trans = db.transaction(["todo"],              IDBTransaction.READ_WRITE);

var store   = trans.objectStore("todo");var request = store.put({

"todo": item.todo,});

}catch(ex) {

onError(ex);}

}

IndexedDB: Add item

Offline strategies for HTML5 web applications

Page 73: Offline strategies for HTML5 web applications - ConFoo13

function modify(item) {try {

var trans = db.transaction(["todo"],              IDBTransaction.READ_WRITE);

var store   = trans.objectStore("todo");var request = store.put(item);

}catch(ex) {

onError(ex);}

}

IndexedDB: Modify item

Offline strategies for HTML5 web applications

Page 74: Offline strategies for HTML5 web applications - ConFoo13

function remove(id) {try {

var trans = db.transaction(["todo"],             IDBTransaction.READ_WRITE);

var store   = trans.objectStore("todo");var request = store.delete(id);

}catch(ex) {

onError(ex);}

}

IndexedDB: Remove item

Offline strategies for HTML5 web applications

Page 75: Offline strategies for HTML5 web applications - ConFoo13

IndexedDB: Read items

Offline strategies for HTML5 web applications

function read () {try {

var trans = db.transaction(["todo"],              IDBTransaction.READ);

var store = trans.objectStore("todo");var keyRange = IDBKeyRange.lowerBound(0);var cursorRequest = store.openCursor(keyRange);

cursorRequest.onsuccess = function(e) {var result = e.target.result;if(!!result == false) {

return;}// @TODO: render result.valueresult.continue();

};}catch(ex) {

onError(ex);}

}

Page 76: Offline strategies for HTML5 web applications - ConFoo13

File API

Offline strategies for HTML5 web applications

Page 77: Offline strategies for HTML5 web applications - ConFoo13

File API

Offline strategies for HTML5 web applications

FileReader API and FileWriter API

Page 78: Offline strategies for HTML5 web applications - ConFoo13

var onError = function(e) {var msg = '';

switch(e.code) {case FileError.QUOTA_EXCEEDED_ERR:

msg = 'QUOTA_EXCEEDED_ERR'; break;case FileError.NOT_FOUND_ERR:

msg = 'NOT_FOUND_ERR'; break;case FileError.SECURITY_ERR:

msg = 'SECURITY_ERR'; break;case FileError.INVALID_MODIFICATION_ERR:

msg = 'INVALID_MODIFICATION_ERR'; break;case FileError.INVALID_STATE_ERR:

msg = 'INVALID_STATE_ERR'; break;default:

msg = 'Unknown Error'; break;};

alert("Error: " + msg);};

File API: Preparations

Offline strategies for HTML5 web applications

Page 79: Offline strategies for HTML5 web applications - ConFoo13

// File system has been prefixed as of Google Chrome 12window.requestFileSystem = window.requestFileSystem ||    window.webkitRequestFileSystem;

window.BlobBuilder = window.BlobBuilder ||     window.WebKitBlobBuilder;

var size = 5 * 1024*1024; // 5MB

File API: Preparations

Offline strategies for HTML5 web applications

Page 80: Offline strategies for HTML5 web applications - ConFoo13

// request quota for persistent storewindow.webkitStorageInfo.requestQuota(

PERSISTENT,size,function(grantedBytes) {

window.requestFileSystem(PERSISTENT,grantedBytes,function(fs) {

// @TODO: access filesystem}

}}

}

File API: Requesting quota

Offline strategies for HTML5 web applications

Page 81: Offline strategies for HTML5 web applications - ConFoo13

Offline strategies for HTML5 web applications

Page 82: Offline strategies for HTML5 web applications - ConFoo13

function add(item) {  window.webkitStorageInfo.requestQuota(

  PERSISTENT,  size,  function(grantedBytes) {

  window.requestFileSystem(  PERSISTENT,  grantedBytes,  function(fs){

  writeToFile(fs, item);  },  onError

  );  },  function(e) {

  onError(e);  }

  );  },

File API: Add item

Offline strategies for HTML5 web applications

Page 83: Offline strategies for HTML5 web applications - ConFoo13

File API: Add item

Offline strategies for HTML5 web applications

function writeToFile(fs, item) {fs.root.getFile(

'todo.txt',{

create: true},function(fileEntry) {

fileEntry.createWriter(function(fileWriter) {

var bb = new window.BlobBuilder();bb.append(JSON.stringify(item)+

                          "\n");

fileWriter.seek(fileWriter.length);fileWriter.write(

                          bb.getBlob('text/plain'));}, onError

);}, onError

);};

Page 84: Offline strategies for HTML5 web applications - ConFoo13

File API: Read items

Offline strategies for HTML5 web applications

function read() {  window.webkitStorageInfo.requestQuota(

  PERSISTENT,  size,  function(grantedBytes) {

  window.requestFileSystem(  PERSISTENT,  grantedBytes,  function(fs){

  readFromFile(fs);  },  onError

  );  },  function(e) {

  onError(e);  }

  );}

Page 85: Offline strategies for HTML5 web applications - ConFoo13

function readFromFile(fs) {fs.root.getFile(

'todo.txt',{

create: true},function(fileEntry) {

fileEntry.file(function(file){var reader = new FileReader();reader.onloadend = function(e) {

if (evt.target.readyState ==     FileReader.DONE) {    // process this.result}

};reader.readAsText(file);

});}, onError

);}

File API: Read items

Offline strategies for HTML5 web applications

Page 86: Offline strategies for HTML5 web applications - ConFoo13

Am I online?

Offline strategies for HTML5 web applications

Page 87: Offline strategies for HTML5 web applications - ConFoo13

document.body.addEventListener("online", function () {  // browser is online!}

document.body.addEventListener("offline", function () {  // browser is not online!}

Am I online?

Offline strategies for HTML5 web applications

Page 88: Offline strategies for HTML5 web applications - ConFoo13

$.ajax({  dataType: 'json',  url: 'http://myappurl.com/ping',  success: function(data){    // ping worked  },  error: function() {    // ping failed ­> Server not reachable  }});

Am I online? Another approach...

Offline strategies for HTML5 web applications

Page 89: Offline strategies for HTML5 web applications - ConFoo13

Browser support?

Offline strategies for HTML5 web applications

App Cache Web Storage WebSQL IndexedDB File API Data URI

IE 10.0 8.0 10.0 10.0 - 8.0*

Firefox 11.0 11.0 11.0 11.0 19.0 16.0

Chrome 18.0 18.0 18.0 18.0 18.0 18.0

Safari 5.1 5.1 5.1 - - 5.1

Opera 12.1 12.1 12.1 - - 12.1

iOS Safari 3.2 3.2 3.2 - - 3.2

Android 2.1 2.1 2.1 - - 2.1

Source: http://caniuse.com

Page 90: Offline strategies for HTML5 web applications - ConFoo13

Storage limitations?

Offline strategies for HTML5 web applications

Page 91: Offline strategies for HTML5 web applications - ConFoo13

Storage limitations?

Offline strategies for HTML5 web applications

All storage technologies are limited by quotas. Be aware of what you do!

Page 92: Offline strategies for HTML5 web applications - ConFoo13

Storage limitations?

Offline strategies for HTML5 web applications

App Cache Web Storage WebSQL IndexedDB File API

iOS 5.1 10 MB 5 MB 5 MB 5 MB

Android 4 unlimited 5 MB ? ?

Safari 5.2 unlimited 5 MB 5 MB 5 MB

Chrome 18 5 MB 5 MB unlimited unlimited unlimited

IE 10 50 MB 10 MB 500 MB 500 MB

Opera 11 50 MB 5 MB 5 MB 5 MB

Firefox 11 unlimited 10 MB 50 MB 50 MB

Page 93: Offline strategies for HTML5 web applications - ConFoo13

Thank you!

Page 94: Offline strategies for HTML5 web applications - ConFoo13

http://joind.in/7913