Friday, March 29, 2013

Busting AppCache with Iframes

‹prev | My Chain | next›

I lost internet connectivity for a time yesterday and noticed something bothersome: many of the items from the ICE Editor's application cache did not actually seem to be in cache. After closer inspection with the network console, these items really are being fetched over the network:



All of the items in the network tab are listed in the application cache:
CACHE MANIFEST
# 2013-03-12

CACHE:
/favicon.ico
/Three.js
/Tween.js
/physi.js
/Mouse.js
/Scoreboard.js
/ChromeFixes.js
/ammo.js
/physijs_worker.js
editor.css
files/inconsolata.woff
js/editor.js
js/appcache.js
js/rawdeflate.js
js/rawinflate.js
js/ace/mode-css.js
js/ace/ace.js
js/ace/theme-chrome.js
js/ace/theme-textmate.js
js/ace/mode-html.js
js/ace/worker-javascript.js
js/ace/keybinding-emacs.js
js/ace/mode-javascript.js
If I switch over to Chrome's resources tab, I can verify that these items are, in fact, in the application cache:



So what gives?

I would guess that at least part of the problem stems from nature of the ICE Code Editor. The visualization layer resides in a separate frame from the actual code editor. The actual application cache manifest attribute is on the main page layer that holds the code editor. In the code editor, I start code with <script> tags that pull in libraries like Three.js and Physijs:
<body></body>
<script src="/Three.js"></script>
<script src="/physi.js"></script>
<script>
  // Actual code goes here...
</script>
This code is then written to a separate frame. Thus, this separate frame has its own HTML document. More importantly, the visualization layer has its own HTML document without an appcache manifest attribute that the code editor has:
<html manifest="editor.appcache">
...
I can also see this in Chrome's resources tab where the Three.js and associated libraries are linked only from the blank, visualization layer frame and not from the appcache main page:



That makes me wonder if this is not as simple as explicitly loading Three.js in the editor page even though it will not be used by that page:
<!DOCTYPE html>
<html manifest="editor.appcache">
  <head>
    <title>code editor</title>
    <!-- other libraies and CSS -->
    <script src="/Three.js"></script>
  </head>
  <body>
  </body>
</html>

And that seems to work. The Three.js library is loaded from cache (and there is no subsequent load from the server):



Unfortunately, this is not the end of my troubles. Any time that an update is made to the code, the visualization frame is destroyed and replaced with a new frame. When the new frame references script libraries, it does end up making a request to the server:



I next modify the ICE code to reuse the same iframe element (instead of removing the iframe element entirely and creating a new one):
var update = function () {
  // ...
  var iframe;
  if ( preview.children.length > 0 ) {
    iframe = preview.children[0];
  }
  else {
    iframe = document.createElement( 'iframe' );
    // ...
    preview.appendChild( iframe );
  }

  var content = iframe.contentDocument || iframe.contentWindow.document;

  content.open();
  content.write(
    '<html manifest="http://localhost:3000/editor.appcache">' +
    editor.getValue() +
    '</html>'
  );
  content.close();
};
Unfortunately, this has no effect on the behavior. The initial load of the editor and generation of the preview / visualization frame obtains Three.js from appcache, but subsequent updates to the preview result in request to the server.

The last thing that I try tonight is to grab a reference to the frame's <body> in an attempt to set the innerHTML. Let's just say that there is a reason that Mr.doob did not do this in the original code editor. Performance is atrocious, bordering on locking up my machine. This clearly will not work for a preview layer that needs to redraw after every tiny code change.

I am out of ideas to try tonight. I will sleep on it and hope for inspiration tomorrow.


Day #705

No comments:

Post a Comment