OnConnectionLost: The life of an offline web application - JSUnconf 2015

Preview:

Citation preview

J S U n c o n f 2 0 1 5

ON CONNECTION LOSTThe life of an offline web application &

war stories about generating PDFs in the browser

#jsunconf #offlinefirst @thoughtworks

@sgrewenig @jthoenes

OFFLINE ??!

WHAT ISOFFLINE ?

STUPIDCLIENT

MORE LOGICCLIENT-SIDE

“INDEPENDENT”CLIENT

WHY ?

HOW ?

CLIENT AVAILABLE OFFLINE

2 DATA AVAILABLE OFFLINE

3 DATA CHANGES OFFLINE

1

CLIENT AVAILABLE OFFLINE1

YOU LEARNED ABOUT APPLICATION CACHE ALREADY, RIGHT?

14

APP CACHE

APP CACHE

APP CACHE

INDEX.HTML

1 <!doctype html> 2 <html ... manifest="appcache.manifest"> . <!-- (...) --> 54 </html>

APPCACHE.MANIFEST 1 CACHE MANIFEST 2 # rev 1 - 2014-10-03T13:50:18.799Z 3 4 CACHE: 5 404.html 6 favicon.ico 7 scripts/scripts.js # (...) 111 112 NETWORK: 113 * 114 115 FALLBACK: 116 / /offline.html

APPCACHE.MANIFEST 1 CACHE MANIFEST 2 # rev 1 - 2014-10-03T13:50:18.799Z 3 4 CACHE: 5 404.html 6 favicon.ico 7 scripts/scripts.js # (...) 111 112 NETWORK: 113 * 114 115 FALLBACK: 116 / /offline.html

APPCACHE.MANIFEST 1 CACHE MANIFEST 2 # rev 1 - 2014-10-03T13:50:18.799Z 3 4 CACHE: 5 404.html 6 favicon.ico 7 scripts/scripts.js # (...) 111 112 NETWORK: 113 * 114 115 FALLBACK: 116 / /offline.html

APPCACHE.MANIFEST 1 CACHE MANIFEST 2 # rev 1 - 2014-10-03T13:50:18.799Z 3 4 CACHE: 5 404.html 6 favicon.ico 7 scripts/scripts.js # (...) 111 112 NETWORK: 113 * 114 115 FALLBACK: 116 / /offline.html

APPCACHE.MANIFEST 1 CACHE MANIFEST 2 # rev 1 - 2014-10-03T13:50:18.799Z 3 4 CACHE: 5 404.html 6 favicon.ico 7 scripts/scripts.js # (...) 111 112 NETWORK: 113 * 114 115 FALLBACK: 116 / /offline.html

EVENTS

CHECKING DOWNLOADING PROGRESS UPDATE READY

ADDITIONAL CACHE

CLIENT AVAILABLE OFFLINE

2 DATA AVAILABLE OFFLINE

1

31

//Store localStorage.town = “Antwerpen”

//Retrieve alert(localStorage.town)

WEBSTORAGEEasy to use key/value store Synchronous API

INDEXED DB

33

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

10 var dbRequest = indexedDB.open('db_name', ‘1’);

31 var trans = database.transaction(['name'], ‘readonly'); 32 var store = trans.objectStore('name'); 33 var getRequest = store.get('4'); 34 getRequest.onsuccess = // …

42 var index = store.index('stockAmount'); 43 var cursorRequest = index.openCursor(IDBKeyRange.lower(15)); 44 cursorRequest.onsuccess = // ...

THE API

MIGRATIONS

ONUPGRADE

NEEDED

FILESYSTEM APIFILE API

44

ADD IMAGE

filesystem:http://thedomain/persistent/xyz.jpg

45

GET IMAGE

IE 106.1YES YEShttp://caniuse.com/#search=fileapi

YES NONONOhttp://caniuse.com/#search=filesystem

CLIENT AVAILABLE OFFLINE

2 DATA AVAILABLE OFFLINE

3 DATA CHANGES OFFLINE

1

DATA SYNCHRONISATION

CAPTURING1 CHANGES

QUEUE2

PROCESSING3

<<<<<<< HEAD

Hamburger is better than Berliner.=======

Berlin is better than Hamburger.>>>>>>> d237ef28dc3fab5dcccc63f580bfa7780f

OR

SIZE OF DATA ?

STRUCTURE OF DATA ?

SENSITIVE DATA ?

POTENTIAL FOR DATA CONFLICTS ?

BROWSER SUPPORT ?

AMOUNT OF FUNCTIONALITY TO WORK OFFLINE ?

61

CHALLENGE REQUIREMENTS

OFFLINE FIRST & EARLY

63

EXPLORE THE POSSIBILITIES

PDF IN THE BROWSER

"sections": [{ "blocks": [{ "contentItems": [ { "uid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "wysiwyg": "<p>Decorative <i>deer</i> figures in a set of 2<\/p><img our-src=“aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.png”>” }, { "libraryItemUid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "uid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "wysiwyg": "<p>There may be <strong>no sign</strong> of a seam in the material. [FT-PLACEHOLDER]<\/p>" }, { "libraryItemUid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "uid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "wysiwyg": "<p>Set comprises a large deer and a small deer [FT-PLACEHOLDER]<\/p>" },

HAVE A LOOK !

67

USE THE BROWSER TO PRINT?

68

var doc = new jsPDF();doc.text(20, 20, 'Hello world.');doc.save('Test.pdf');

https://github.com/MrRio/jsPDF

PDFDocument = require 'pdfkit'

doc = new PDFDocumentdoc.pipe fs.createWriteStream('output.pdf')doc.font('fonts/PalatinoBold.ttf') .fontSize(25) .text('Some text with an embedded font!', 100, 100)

doc.addPage() .fontSize(25) .text('Here is some vector graphics...', 100, 100)

doc.end()https://github.com/devongovett/pdfkit

pdfMake.createPdf({ content: [ { text: 'This paragraph will have a bigger font', fontSize: 15 }, { text: [ { text: 'restyle part of it and make it bigger ', fontSize: 15 }, 'than the rest.' ] } ]}).open();

https://github.com/bpampuch/pdfmake

SHORT DEMO?

73

74

HTML -> PDF PARSER

75

PAGE BREAKS

76

LANDSCAPE

77

95 CHARACTERS

78

IMAGE WRAPPING

79

https://github.com/TW-QEN/pdfmake#develop

THANKS@SGREWENIG @JTHOENES@THOUGHTWORKS

IE 10YESYES YEShttp://caniuse.com/#search=appcache

IE 107.1YES YEShttp://caniuse.com/#search=indexeddb

YESYESYES YEShttp://caniuse.com/#search=webstorage

Recommended