‹prev |
My Chain |
next›
I need to take a (hopefully) quick break from my regularly scheduled
Three.js programming to answer a question that has vexed me for a couple of night now: how to expire the HTML5 application cache? Actually, most of the cache is easy to expire, but there is one part that I cannot suss.
The application cache is a mechanism for creating offline applications.
Mr Doob's Amazing
Code Editor uses it so that users can still work with the Code Editor even when not connected to the Internet. Since this is an editor, offline capability seems like a good thing.
The application cache is established by the presence of the
manifest attribute on the
<html> element of a web page:
<!DOCTYPE html>
<html manifest="editor.appcache">
<head>
<title>code editor</title>
The
appcache manifest file then describes the elements that are cacheable, those that should always be requested over the network, and any fallback. The manifest is stored in the same location as the web page. The manifest for Mr Doob's Code Editor looks like:
CACHE MANIFEST
# 2012-09-10
CACHE:
/favicon.ico
index.html
files/inconsolata.woff
js/editor.js
js/appcache.js
js/rawdeflate.js
js/rawinflate.js
js/codemirror/codemirror.css
js/codemirror/codemirror.js
js/codemirror/mode/css.js
js/codemirror/mode/htmlmixed.js
js/codemirror/mode/javascript.js
js/codemirror/mode/xml.js
NETWORK:
*
An application cache manifest needs to start with the
CACHE MANIFEST directive. The
CACHE directive introduces a list of files that will be loaded into cache. These files will be available offline and not requested from the server—even during a hard reload. The NETWORK directive introduces the files that will always be loaded over the Internet—even if they are needed by the application. In the case of the Code Editor, the catch-all of '*' is used to indicate that anything not explicitly referenced by
CACHE but needed by the application, should be loaded via the internet.
As for my woes, it begins with the commented date immediately following the opening
CACHE MANIFEST directive. The comment has no effect on the application cache itself. What it does serve to do is to expired the application cache. If the network is available, when I load up the application at
http://gamingJS.com/code-editor no files are loaded
except for the application cache manifest.
This presents a problem if
js/editor.js was updated. Unless the application cache has changed, the browser will not reload
js/editor.js. Even during a hard reload. Even if the user clears her cache and reloads. The
js/editor.js file remains in application cache.
Since no new files have been added to the application, I cannot add a file to the manifest, so the convention is to update the timestamp after
CACHE MANIFEST to force a reload. And this works just fine:
My problem is that, the code editor is very new. At the very least, I need to make a few changes to it. Mr Doob has made clear his intention to make major changes as well. I need to reference it in
Gaming JavaScript at the
http://gamingjs.com/code-editor. But that URL is
not in the application manifest. The actual page of
index.html is included in the manifest, but this is not what is stored in application cache.
Unfortunately, in its early days, much of Code Editor is stored in this web page. When there are changes, I have no way to update them. I (and anyone else with the old cached application) are stuck with the original version of the application. The only solution is to open up
chrome://appcache-internals/ to manually remove the old version. This is not exactly ideal.
My ultimate solution to this conundrum is a decidedly pre-HTML5 solution: <script>
if (window.location.href.indexOf('.html')) < 0 {
window.location.href = 'index.html'
}
</script>
And that seems to do the trick.
Dang it. That was a ton of explanation for a very simple solution. I wish I had thought of that sooner. But, like I said at the outset, this had been bugging me for days. Writing it down turned out to be my rubber ducky.
Update: In the end, I don't think that works as desired. Subsequent reload are not picking up changes. So I am forced to adopt the
HTML5 Rocks swapCache() solution:
// 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 to get the new hotness.
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);
}, false);Day #505