Last active
May 2, 2017 12:00
-
-
Save GianlucaGuarini/669265541009eca1ad728eb7f28504bb to your computer and use it in GitHub Desktop.
Cache a whole SPA website and its assets via app cache, service workers and localstorage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"secret-message": "hello" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CACHE MANIFEST | |
# 2017-04-04 v1.0.0 | |
/style.css | |
/index.js | |
NETWORK: | |
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html manifest='demo.appcache'> | |
<head> | |
<title>demo</title> | |
<link rel='stylesheet' href='style.css'> | |
</head> | |
<body> | |
<h1>Hello</h1> | |
<p></p> | |
<img src='https://static.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg'> | |
<script src='index.js'></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Get a json file via ajax request, the `fetch` was not used on purpose | |
* @param { String } url - json url | |
* @returns { Promise } deferred return of the json file contents | |
*/ | |
function getJSON(url) { | |
var request = new XMLHttpRequest() | |
request.open('GET', url, true) | |
return new Promise((resolve, reject) => { | |
request.onload = function() { | |
if (request.status >= 200 && request.status < 400) { | |
// Success! | |
var data = JSON.parse(request.responseText) | |
resolve(data) | |
} else { | |
// We reached our target server, but it returned an error | |
reject('unkown error') | |
} | |
} | |
request.onerror = reject | |
request.send() | |
}) | |
} | |
/** | |
* Try to start the service worker if supported | |
* @returns { Promise } - resolve in any case | |
*/ | |
function startServiceWorker() { | |
return new Promise((resolve, reject) => { | |
if ('serviceWorker' in navigator && navigator.onLine) { | |
navigator.serviceWorker.register('service-worker.js', { | |
scope: './' | |
}) | |
navigator.serviceWorker.ready.then(resolve) | |
} else { | |
resolve() | |
} | |
}) | |
} | |
/** | |
* Application boot event | |
* @param { Object } data - application data | |
*/ | |
function onReady(data) { | |
document.querySelector('p').innerHTML = `${data['secret-message']} ${new Date()}` | |
} | |
/** | |
* Boot the app using fallback data | |
*/ | |
function fallbackData() { | |
console.log('loading cached fallback data') | |
onReady(JSON.parse(localStorage.getItem('json'))) | |
} | |
/** | |
* Try to start the service worker | |
*/ | |
startServiceWorker().then(() => { | |
// if not online it's not even worth to try to fetch new data | |
if (navigator.onLine) { | |
console.log('fetching new data') | |
getJSON('/data.json').then(json => { | |
localStorage.setItem('json', JSON.stringify(json)) | |
onReady(json) | |
}).catch(fallbackData) | |
} else { | |
console.log('loading offline') | |
fallbackData() | |
} | |
}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// forked from https://serviceworke.rs/strategy-network-or-cache.html | |
var CACHE = 'network-or-cache' | |
// On install, cache some resource. | |
self.addEventListener('install', function(evt) { | |
console.log('The service worker is being installed.') | |
// Ask the service worker to keep installing until the returning promise | |
// resolves. | |
evt.waitUntil(precache()) | |
}) | |
// On fetch, use cache but update the entry with the latest contents | |
// from the server. | |
self.addEventListener('fetch', function(evt) { | |
console.log('The service worker is serving the asset.') | |
// Try network and if it fails, go for the cached copy. | |
evt.respondWith(fromNetwork(evt.request, 400).catch(function () { | |
return fromCache(evt.request) | |
})) | |
}) | |
// Open a cache and use `addAll()` with an array of assets to add all of them | |
// to the cache. Return a promise resolving when all the assets are added. | |
function precache() { | |
return caches.open(CACHE).then(function (cache) { | |
return cache.addAll([ | |
'./index.html', | |
'./index.js', | |
'./style.css' | |
]) | |
}) | |
} | |
// Time limited network request. If the network fails or the response is not | |
// served before timeout, the promise is rejected. | |
function fromNetwork(request, timeout) { | |
return new Promise(function (fulfill, reject) { | |
// Reject in case of timeout. | |
var timeoutId = setTimeout(reject, timeout) | |
// Fulfill in case of success. | |
fetch(request).then(function (response) { | |
clearTimeout(timeoutId) | |
fulfill(response) | |
// Reject also if network fetch rejects. | |
}, reject) | |
}) | |
} | |
// Open the cache where the assets were stored and search for the requested | |
// resource. Notice that in case of no matching, the promise still resolves | |
// but it does with `undefined` as value. | |
function fromCache(request) { | |
return caches.open(CACHE).then(function (cache) { | |
return cache.match(request).then(function (matching) { | |
return matching || Promise.reject('no-match') | |
}) | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
background: #222; | |
color: white; | |
} | |
img { | |
width: 100%; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment