Re: Out of order JS file execution in WebKit

Werner Thie <[email protected]> Wed, 14 Apr 2010 16:30:39 +0200
Newsgroups gmane.comp.python.quotient.dev
Organization THIEngineering AG
Message-ID <[email protected]>
On 13.04.2010 03:56, [email protected] wrote:
> On 12 Apr, 06:53 pm, [email protected] wrote:
>> This definitely makes sense. I got the sinking feeling that I'm loosing
>> this really great and simple extension of JS and the whole nevow/athena
>> LivePage ecosystem too when I encountered this WebKit problem first. If
>> you could elaborate on where to bring in the wrapper func you proposed
>> I
>> would be more than happy.
>
> So, a few tips to get started:
>
> Athena already keeps track of any widget which has been dropped into the
> page somehow but for which the javascript object hasn't yet been
> initialized.  The reasons for this are a bit obscure, but the result is
> Nevow.Athena.Widget._waitingWidgets.   If you search for _waitingWidgets
> in Nevow/nevow/js/Nevow/Athena/__init__.js, you'll find a couple
> functions which interact with this.  One, _widgetNodeAdded, gets called
> from the DOM when a new widget appears in it that needs to be
> initialized.  Then, some time later, _instantiateWidgets gets called and
> goes over _waitingWidgets instantiating the things that need to be
> instantiated.
>
> That's all interesting because it's _sort of_ like what you might want
> to happen with modules.  Keep track of which ones have been loaded but
> are waiting on dependencies before actually being evaluated, and then at
> some later point actually doing the evaluation.
>
> _waitingWidgets triggers the "later point" using a timer event, which
> sucks, but there was probably some reason for it.  Fortunately, for
> module loading, it's not necessary to resort to timing.  Instead, the
> event will be that some /other/ javascript module was finally loaded and
> evaluated.
>
> Next, in Nevow/nevow/athena.py, there's MappingResource.  This is the
> thing that's supposed to be used to actually serve up the source of the
> JavaScript modules.
>
> If you change what its `resourceFactory` method returns, then you're
> changing what javascript is served up when a browser tries to load
> athena modules.  As a first stab, you could try loading up the contents
> of the named file yourself, mangling it somehow, and returning it in a
> static.Data.
>
> Ultimately it would be nice if Athena's javascript weren't tied to files
> on disk, but that's a concern for later on I think.
>
> As for the actual mangling itself, it may be a simple matter of wrapping
> the entire module source in some boilerplate for deferring evaluation
> and setting up the necessary triggers.  As far as the wrapping goes, I'm
> really just talking about simple string manipulation.  Like:
>
>      moduleSource = """
> setupSomeState("%(moduleName)s, function() {
> %(moduleBody)s
> });
> """ % {'moduleName': whateverName, 'moduleBody': originalJSSource}
>
> Nothing fancier than that.  I think it should work.  Perhaps the only
> tricky bit is that the module name may not be immediately easily
> accessible, but I'm sure there's a way to deal with that.
>
> Hope this helps,
> Jean-Paul
>
> _______________________________________________
> Divmod-dev mailing list
> [email protected]
> http://divmod.org/cgi-bin/mailman/listinfo/divmod-dev
Hello Jean-Paul

I decided to do a first go around with handcrafted wrapper code for the 
JS modules in question like you suggested and it worked no problem. 
Filling the boilerplate with content seems to me a little bit more of a 
challenge, because after some debugging in the MappingResource I don't 
yet see a way to get at the information in the import statements without 
reparsing the file (which I assume is a no go).

Do you have a suggestion on how to proceed?

Thxs, Werner

modulesWaiting = {};

function moduleLoaded(module) {
   modulesWaiting[module] = null;
   Divmod.debug("moduleLoaded", "loaded module: " + module);
}

function waitForModules(module, f) {
   modulesWaiting[module] = f;
   for (var m in modulesWaiting) {
     if (modulesWaiting[m])
       modulesWaiting[m]();
   }
}

//// boilerplate wrapper code
//waitForModules(%(modulename)s, function() {
//  var deps = [%(depsFromImport)s];  //comma separated list of modules	
//  var loaded = true;
//  for (var i=0; i<deps.length; i++)
//    loaded = loaded && (deps[i] != null);
//  if (loaded) {
//    //here comes the source, Luke
//
//    moduleLoaded(%(modulename)s);
//  }
//});