With travel and prep for OSCON, I am going to try to keep posts brief this week. Still, the gods of the chain must be appeased, so posts there must be. In today's, I hope to nail down one of the two manual processes in deployment of the ICE Code Editor: generating the application cache manifest file (the other is copying Dart packages from system cache).
Application cache is a newish feature of modern browsers that allow sites to cache files in browsers. This is done with a
manifestattribute on the
<html>tag of a page:
<!DOCTYPE html> <html manifest="editor.appcache"> <!-- ... --> </html>The format of the appcache file is a plain text file. Inside, it typically contains three sections: the manifest (opens the manifest and contains meta-information), the cache (contains a list of files to be cached) and a listing of files that should be fetched from the network rather than cached (typically a wildcard to denote everything not explicitly listed as being cached).
I am going to build this with a Bash script. Sometimes there is nothing better than a simple Bash script to get the job done. I toyed with the idea of a script to replace just a portion of the existing appcache file, but complete regeneration seems more robust. If I ever have to make a change to the structure of the appcache file, I will not have to worry about breaking this script by moving around important anchor text.
I start by declaring a variable to hold the name of the appcache file:
#!/bin/sh APPCACHE=editor.appcacheI have no intention of changing the name of the file—I use a variable as a matter of taste to keep the rest of the code clean.
Next up, I wipe the old appcache file and write the manifest section of the file:
## # Manifest echo 'CACHE MANIFEST' > $APPCACHE date +'# %Y-%m-%d %H:%M:%S' >> $APPCACHE echo >> $APPCACHEI start with a single file redirect (
>) so that
echo 'CACHE MANIFEST'overwrites the previous contents of the file. All subsequent operations will be done with the append redirect (
>>). I am not worrying about making a backup because the generated code will be checked into source code—I already have a backup.
After the manifest directive, I add a comment containing the date to the appcache file—the
datecommand's support for strftime-like formatting comes in handy here. Browser application cache does not use this information—the leading pound sign is a comment in appcache files. The purpose of the time stamp is solely to force the web server to respond with a 200 instead of 304. That is, a change in the content of the file—even a comment—will tell the server that this appcache file has changed and that it should not respond that it is NOT MODIFIED (304).
It is vitally important that this timestamp change whenever cached files change. If the server replies that the appcache file is unchanged, then no updated files will be loaded by the browser. I could change each and every file that is listed in the appcache manifest, but if the appcache file is unchanged, the browser will continue to use the old versions. If files are added or subtracted from the list of cached files in the appcache file, that would count as a change to the appcache file. More often than not, changes involve only modifying existing files. And a timestamp comment is the best way to communicate that some change awaits.
For the first section of cache—the files I want to make available to the programmers using ICE to make 3D animations—I list them manually:
## # Cache echo 'CACHE:' >> $APPCACHE # Fixed files used within the editor for creating Three.js worlds: cat <<EOF >> $APPCACHE /favicon.ico /Three.js /Tween.js /Detector.js /physi.js /Mouse.js /Scoreboard.js /ChromeFixes.js /ammo.js /physijs_worker.js EOFI am
cating a HEREDOC to accomplish this. The
catcommand would normally echo the contents of a file. By supplying it with a HEREDOC, I tell
catto read from here.
Next, I have to echo the
main.dartfile into the list of cached files in
# Dart script referenced in a SCRIPT tag: echo main.dart >> $APPCACHE echo >> $APPCACHENo production browser in the world is going to do anything with that file, but it is explicitly referenced in a SCRIPT tag. For this reason, it must be in application cache to prevent a network request.
Last, I use my
# Dart and JS code used to make the editor: find | \ grep -e \\.js$ -e \\.map$ -e \\.html$ -e \\.css$ | \ grep -v -e unittest -e /lib/ | \ sed 's/^\.\///' \ >> $APPCACHEI add a small
sedscript to the chain to remove leading
./from the find output:
./part.js ./index.html ./main.dart.js.map ...That does it for the CACHED section of my application cache file.
All that remains is a wildcard entry in the NETWORK section:
## # Network cat <<EOF >> $APPCACHE NETWORK: * EOFThat is all there is to it. After running the script, the only difference in
editor.appcacheis the timestamp:
➜ ice-beta git:(gh-pages) ✗ git diff -u editor.appcache diff --git a/ice-beta/editor.appcache b/ice-beta/editor.appcache index 90d2ba8..ebaedef 100644 --- a/ice-beta/editor.appcache +++ b/ice-beta/editor.appcache @@ -1,5 +1,5 @@ CACHE MANIFEST -# 2013-07-20 +# 2013-07-22 10:26:40 CACHE: /favicon.icoSo I have successfully written an automated script that ought to keep up with the changing files in ICE. The full, working script is:
#!/bin/sh APPCACHE='editor.appcache' ## # Manifest echo 'CACHE MANIFEST' > $APPCACHE date +'# %Y-%m-%d %H:%M:%S' >> $APPCACHE echo >> $APPCACHE ## # Cache echo 'CACHE:' >> $APPCACHE # Fixed files used within the editor for creating Three.js worlds: cat <<EOF >> $APPCACHE /favicon.ico /Three.js /Tween.js /Detector.js /physi.js /Mouse.js /Scoreboard.js /ChromeFixes.js /ammo.js /physijs_worker.js EOF # Dart script referenced in a SCRIPT tag: echo main.dart >> $APPCACHE echo >> $APPCACHE # Dart and JS code used to make the editor: find | \ grep -e \\.js$ -e \\.map$ -e \\.html$ -e \\.css$ | \ grep -v -e unittest -e /lib/ | \ sed 's/^\.\///' \ >> $APPCACHE ## # Network cat <<EOF >> $APPCACHE NETWORK: * EOFThat is a fine stopping point for today. Up tomorrow, I will try to automate the copying of system pub packages into a deployment.