Sunday, June 9, 2013

AppCache Serendipity with a Dart Assist

‹prev | My Chain | next›

Some time ago, I found that my application cache-based code editor did not actually cache the application. The problem was that my code editor regenerated iframes and each time the new iframe loaded, it made a request outside of the application cache. Even if the resource actually resided in the application cache, the browser would ignore it, resulting in a web request.

My hypothesis is that dynamically generated iframes are not considered part of the application cache. That might explain why the initial load would pull resources from application cache, but subsequent updates would miss appcache.

Recently, I realized that the Dart-based ICE Code Editor does not dynamically generate iframes. I did not architect the application this way by choice. Rather Dart prohibits manipulating frames. Instead I use message passing between the editor layer and a static preview iframe. So maybe, just maybe, my Dart version is already fully compatible with application cache.

As they say, there is one way to find out: to try it. This is a bit of a bother because ICE is not yet in Dart Pub. I may have to rectify that sooner than I expected. But eventually, I sync up my local GitHub pages repository with the most recent ICE. After pub installing the necessary dependencies, I add all of these files to my editor.appcache:
find . -type f >> editor.appcache
This results in a file that looks something like:
CACHE MANIFEST
# 2013-06-09:v02

CACHE:
/favicon.ico
/Three.js
/Tween.js
/Detector.js
/physi.js
/Mouse.js
/Scoreboard.js
/ChromeFixes.js
/ammo.js
/physijs_worker.js

main.dart
index.html
main.dart.js.map
main.dart.js
packages/js/js.dart
packages/js/src/wrapping/js/object_to_map_adapter.dart
...

NETWORK:
*
(I have to manually get those last two lines in the right place)

Then I add the manifest attribute to the entry page:
<!DOCTYPE html>
<html manifest="editor.appcache">
  <head>
    <title>code editor</title>
    <meta charset="utf-8">
    <script src="appcache.js"></script>
    <script src="packages/browser/dart.js"></script>
    <script src="main.dart" type="application/dart"></script>
  </head>
  <body>
  </body>
</html>
Since this is a GitHub pages site, I fire up Jekyll to test it locally:
➜  gamingjs git:(gh-pages) ✗ jekyll --auto --server
And, amazingly, it seems to work. When I make a change in the editor, the iframe is updated, reloading various JavaScript libraries that ought to be in application cache. But the only request that the server sees is a request checking to see if the application cache file has updated:
...
[2013-06-09 21:50:34] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
localhost - - [09/Jun/2013:21:50:34 EDT] "GET /ice-beta/editor.appcache HTTP/1.1" 304 0
- -> /ice-beta/editor.appcache
Could it be? Do I really have a working iframe application cache?

Indeed I do. I shut down both my browser and my web server. When I start the browser back up with no web server, I can load the application, see the preview and see updates when I make changes. In fact, I can see 404s for the appcache manifest in my JavaScript console as I see the preview:



I take a bit of time to verify that this problem has not been solved in the browser itself (I point gamingjs.com to 127.0.0.1 in /etc/hosts). It really seems that this static iframe with message passing solution has done the trick. I still need to push this out to beta to verify for certain. Since I was able to verify the problem locally when I first ran into the issue, I have a fair degree of confidence that I have a good solution here.

The crazy thing is that I was frustrated and more than a bit annoyed with Dart when I was forced to pass messages to iframes. It turns out that Dart's security consciousness forced me into an architecture that is both more secure and application cache compliant.


Day #777

No comments:

Post a Comment