A presentation at Frontend United in in Utrecht, Netherlands by Jeremy Keith
Going Offline
adactio.com
adactio.com
resilientwebdesign.com
2005
JavaScript When someone mouses over a link, make it look different. When someone fills out a form, make sure the inputs are valid.
JavaScript Find stuff and do stuff to it.
JavaScript Find stuff and do stuff to it. jQuery
JavaScript Find stuff and do stuff to it. $(‘.stuff’).click(doStuff); jQuery
JavaScript document.querySelector(‘.stuff’) .addEventListener(‘click’, doStuff); Find stuff and do stuff to it. $(‘.stuff’).click(doStuff); jQuery
JavaScript code Logic.
JavaScript Logic. code
2007
Update part of this page with data from a server. Ajax
DOM Scripting Find stuff on this page and do stuff to it. Update part of this page with data from a server. Ajax
DOM Scripting Find stuff on this page and do stuff to it. Update part of this page with data from a server. Ajax
DOM Scripting web worker Ajax
web worker
service worker
2018
example.com
example.com
example.com
example.com
example.com
example.com
page.html styles.css script.js icon.png example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js example.com
serviceworker.js https ://example.com
https
register install active update life cycle
register
install
active
update
update
active
register
register Get the JavaScript file ‘serviceworker.js’
register <script src=”/serviceworker.js”> </script>
register <script src=”/serviceworker.js”> </script>
register <script> navigator.serviceWorker.register(); </script>
register <script> navigator.serviceWorker.register (‘/serviceworker.js’); </script>
register <script> navigator.serviceWorker.register (‘/assets/js/serviceworker.js’); </script>
register <script> navigator.serviceWorker.register (‘/assets/js/serviceworker.js’); </script>
register <script> navigator.serviceWorker.register (‘/serviceworker.js’); </script>
register <script> if (navigator.serviceWorker) { navigator.serviceWorker.register (‘/serviceworker.js’); } </script>
register Get the JavaScript file ‘serviceworker.js’
<script> if (navigator.serviceWorker) { navigator.serviceWorker.register (‘/serviceworker.js’); } </script>register Install the JavaScript file ‘serviceworker.js’
<script> if (navigator.serviceWorker) { navigator.serviceWorker.register (‘/serviceworker.js’); } </script>install
install caching
memory cache browser cache Cache API caching
install precaching
install styles.css script.js icon.png
install styles.css script.js icon.png
install styles.css script.js icon.png
install styles.css script.js icon.png
install styles.css script.js icon.png
install styles.css script.js icon.png
install script.js styles.css icon.png
install
install precaching
precaching When this service worker is installing open a cache and then put a bunch of files in that cache.
precaching When this service worker is installing
precaching When this service worker is installing addEventListener()
precaching When this service worker is installing addEventListener(‘install’)
precaching When this service worker is installing addEventListener(‘install’, function(event) { });
precaching When this service worker is installing addEventListener(‘install’, event => { });
precaching open a cache
precaching open a cache caches.open()
precaching open a cache caches.open(‘files’)
precaching open a cache and then caches.open(‘files’)
precaching open a cache and then caches.open(‘files’).then()
precaching open a cache and then caches.open(‘files’).then( cache => { });
precaching put a bunch of files in that cache.
precaching put a bunch of files in that cache. cache.addAll()
precaching put a bunch of files in that cache. cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’ ]);
precaching
precaching When this service worker is installing addEventListener(‘install’, event => { });
precaching When this service worker is installing open a cache caches.open(‘files’)
precaching When this service worker is installing open a cache and then caches.open(‘files’).then( cache => { });
precaching When this service worker is installing open a cache and then put a bunch of files in that cache. cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’ ]);
precaching When this service worker is installing open a cache and then put a bunch of files in that cache.
precaching addEventListener(‘install’, event => { });
precaching addEventListener(‘install’, event => { caches.open(‘files’) });
precaching addEventListener(‘install’, event => { caches.open(‘files’).then( cache => { }); });
precaching addEventListener(‘install’, event => { caches.open(‘files’).then( cache => { cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’ ]); }); });
precaching addEventListener(‘install’, event => { caches.open(‘files’).then( cache => { cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’ ]); }); });
install
active
cache first When a file is requested try to find the file in the cache first otherwise fetch the file from the network.
cache first When a file is requested
cache first When a file is requested addEventListener()
cache first When a file is requested addEventListener(‘fetch’)
cache first When a file is requested addEventListener(‘fetch’, event => { });
cache first When a file is requested addEventListener(‘fetch’, event => { event.respondWith( ); });
cache first try to find the file in the cache first
cache first try to find the file in the cache first caches.match(event.request)
cache first try to find the file in the cache first caches.match(event.request) .then( response => { })
cache first try to find the file in the cache first caches.match(event.request) .then( response => { return response; })
cache first try to find the file in the cache first otherwise fetch the file from the network. caches.match(event.request) .then( response => { return response; })
cache first try to find the file in the cache first otherwise fetch the file from the network. caches.match(event.request) .then( response => { return response || fetch(event.request); })
cache first When a file is requested try to find the file in the cache first otherwise fetch the file from the network.
cache first addEventListener(‘fetch’, event => { event.respondWith( ); });
cache first addEventListener(‘fetch’, event => { event.respondWith( caches.match(event.request) .then( response => { return response }) ); });
cache first addEventListener(‘fetch’, event => { event.respondWith( caches.match(event.request) .then( response => { return response || fetch(event.request); }) ); });
cache first addEventListener(‘fetch’, event => { event.respondWith( caches.match(event.request) .then( response => { return response || fetch(event.request); }) ); });
cache first
offline first
offline first
offline first
offline first
offline first
offline first
offline first
offline first
offline first precaching cache first install active
css js img precaching cache first
html network first custom offline page
network first
precaching addEventListener(‘install’, event => { caches.open(‘files’).then( cache => { cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’ ]); }); });
precaching addEventListener(‘install’, event => { caches.open(‘files’).then( cache => { cache.addAll([ ‘/css/styles.css’, ‘/js/script.js’, ‘/img/icon.png’, ‘/offline.html’ ]); }); });
network first When a page is requested try to fetch the page from the network first otherwise retrieve the offline page from the cache.
network first When a page is requested addEventListener(‘fetch’, event => { });
network first When a page is requested addEventListener(‘fetch’, event => { if (event.request.headers .get(‘Accept’).includes(‘text/html’) { } });
network first try to fetch the page from the network first event.respondWith( fetch(event.request) .then( response => { return response; }) );
network first otherwise retrieve the offline page from the cache. .catch( error => { return caches.match(‘/offline.html’); })
network first
network first addEventListener(‘fetch’, event => { if (event.request.headers.get(‘Accept’).includes(‘text/html’) { } });
network first addEventListener(‘fetch’, event => { if (event.request.headers.get(‘Accept’).includes(‘text/html’) { event.respondWith( fetch(event.request) .then( response => { return response; }) } }); );
network first addEventListener(‘fetch’, event => { if (event.request.headers.get(‘Accept’).includes(‘text/html’) { event.respondWith( fetch(event.request) .then( response => { return response; }) .catch( error => { return caches.match(‘offline.html’); }) ); } });
network first addEventListener(‘fetch’, event => { if (event.request.headers.get(‘Accept’).includes(‘text/html’) { event.respondWith( fetch(event.request) .then( response => { return response; }) .catch( error => { return caches.match(‘offline.html’); }) ); } });
html network first custom offline page
html network first cache as you go custom offline page
html network cache custom offline page
cache as you go When a page is requested try to fetch the page from the network first and store a copy in the cache otherwise try to retrieve the page from the cache otherwise retrieve the offline page from the cache.
custom offline page offline.html
css js img html cache network network cache fallback
css js img html speed freshness
articles shopping travel games reference
cache on demand articles
cache on demand When the user presses a button put a copy of this page in the cache.
cache on demand page.html
una.im
una.im
una.im
sarasoueidan.com
sarasoueidan.com
archive.dconstruct.org
archive.dconstruct.org
archive.dconstruct.org
archive.dconstruct.org
web app manifest https service worker
web app manifest <link rel=”manifest” href=”/manifest.json”>
web app manifest { } name: “Resilient Web Design”, short_name: “Resilience”, display: “standalone”, start_url: “/”, theme_color: “#5f7995”, icons: { { src: “/icon.png”, sizes: “512x512”, type: “image/png” } }
web app manifest https service worker progressive web app
progressive
progressive
Thank you
Web design is complicated. Web development is complicated. Everything seems to be constantly changing—there’s so much to keep track of. But there’s one thing we can confidently say for sure: websites need an internet connection in order to work. Right? Well, even that is no longer true. Thanks to the powerful technology of service workers, you can now design and develop websites that work offline. This is a game-changer! And now you’ve got something new you need to learn. But don’t worry—Jeremy is here to talk you through a whole range of offline strategies. By the end of this presentation, you’ll have all the knowledge and code you’ll need to free your website from the tyranny of the network connection.
The following resources were mentioned during the presentation or are useful additional information.