Coming to the end of the development cycle of a fairly large & Javascript dependant project, a few issues have cropped up that will probably need resolving before going full production. Im glad that hammett seems to be having similar problems, & it’s not something that has already been solved that I have ignored within MonoRail.
The first is the fact that I have alot of dependencies in javascript files, the front page of the application (& probably where the user will spend a fair amount of time) in particular depends upon Prototype, Scriptaculous, Plotkit & Mochikit and about 20 other random small javascript files, that may or may not need to be included. At the moment my BaseController exposes functions to bring in those javascript files, and code in my layout #includes the relevant nvelocity files. This is ascetically ugly as I am calling these in my controller methods (although it could be done in the views via $controller.IncludeSomeFile). Basically I Got It Working, knowing full well that it was going to be a thorn in my side, ascetically & performance wise. So I want something akin to the Helper attributes that you can decorate your controllers (and perhaps methods) with.
The current Helper system in MonoRail works fine with the scriptaculous & Prototype Helpers at the moment, but the current situation doesnt help with javascript dependencies, or caching/bundling the javascript. Ive learnt to live with manually dealing with dependencies, so that’s not a huge problem per se (I have been developing in .NET for a couple of years now
, but I have a sneaking suspicion that the 40+ javascript files being pulled in is going to exacerbate performance problems, both on the client and server.
Starting afresh on an related project, allowed me to look afresh at the MonoRail offerings, and I of course first went to the ajax related stuff. Nice to see a BehaviourHelper, but my last project used event-selectors as I liked how it works, and hinges on Prototypes $$() support, with the peformance gains and css-selector support that engenders. I also don’t like ‘meta-programming’ as it pertains to the web, as it reminds me too much of the ol’ PHP days:
$BehaviourHelper.Register("someId", "function(el){doSomething(*);}")
my javascript function often ended up with more that just a one liner, very ugly in quoted code within a nvelocity file (no syntax!). So I first baked up a solution for EventSelectors, the patch is here. Read the patch comments for what it does, & how it builds a javascript file that contains all the relevant event selectors for that area/controller/view. I really do like convention over configuration. I hope it doesnt get lost in the castle-devel deluge…
So that’s event selectors sorted, next up I need to look at:
- Bringing in ’standard’ javascript libraries, which may also reference css files.
- Handling dependency trees (i.e scriptaculous upon prototype)
- Bringing in application javascript libraries, using a convention based approach, so your javascript application code is packaged cleanly in a folder structure.
- Handling caching of the dependency trees, and outputting concatenated/compressed javascript, just like RoR!
I’ll be putting up a class designer of my initial class design in my next post.
June 19, 2007 at 8:02 am
Hi, the patch is waiting for some documentation in order to be applied. About the JS, why didnt you just include the js files? Why the BaseController expose them? And even if they do, you could use the [Cache] attribute to force the browser to cache them.
So I think we’re having different problems. Mine is about writing similar ajax code in different projects… And I think a way to solve it would be a nice DSL for js generation. Not sure yet..
June 19, 2007 at 8:52 am
The BaseController exposed them as Helper methods, not as actual url-viewable methods. The generated view still outputted tags, which linked to the relevant js files. SoC badness I know, I was being lazy, I had alot of js dependencies to handle, and not enough time/naus to look at how Castle handled it & whether I could retool it for my javascript needs.
And yes, we are on a different page really, I more need an efficient way to pull in different javascript files depending on my controller/action (i.e not include everything and the kitchen sink for pages that need little javascript), without having a gazillion different layout files for the different controller/actions. But anyway, this is a problem I am looking at atm, there may be some overlap with the issues you are facing. Expect some patches
Btw are you looking for a backwards compatible approach for browsers with no javascript, or is that not an issue?
June 19, 2007 at 2:44 pm
Is there a browser with no js support nowadays?
About the JS, I think it was suggested a helper (JSManager) that could keep track of required js includes. It could work for controllers and view components. But I’m afraid it’s not as easy as it looks…
June 19, 2007 at 7:43 pm
Ideally you want to create javascript with intelissense/compile time validation, etc… something like Script# in combination with MonoRail and a rich javascript UI library (like ExtJS) would be great..
June 26, 2007 at 7:52 am
Hammett,
expect a patch soon for something like JSManager. I have coded up a dependency manager, that at the moment works js library dependency (i.e. scriptaculous -> prototype) and manages redundancies/circular refs. “Bundling” and compression/caching of the outputted libs is next on the list, but I havent gotten around to it. This actually looks to be quite easy (generate a key based on the flattened list of libraries to include & store that somewhere persistent, any suggestions on a good place to store this appreciated)
And no, it wasnt as easy as it seemed when I started coding it!
November 14, 2007 at 9:39 pm
I know I am a little late to the party, but I am a complete MonoRail newbie and am wondering if anything else has been done on coming up with a nice way to handle JavaScript file dependencies and clean injection into the views. Currently, I use the following construct in my ASP.NET projects and am looking at how to do something similar in MonoRail:
If I have a file called Foo.aspx, I have code that will automagically inject a script tag into the file at run-time for a file called Foo.aspx.js if it exists. I would like to do the same in MonoRail, namely I want to have some code that will detect whether a file called Foo.vm.js exists, and if so, inject the script tag into the HTML to include that when the Foo.vm view is used.
Thanks for any advice on this.