My friend Carl has just released a really interesting Javascript library called Frontal. I've had a night to sleep on it and thought I'd share my thoughts.
The key problem Frontal addresses is 'some Javascript needs to be run only on some pages'. There are a few different approaches to this:
Per-page scripts
The first approach is to have lots of Javascripts that only apply for the current page, and insert them in the HEAD of the document:
<head>
<script src="base.js"></script>
<script src="something-page-specific.js"></script>
</head>
Pros:
- You can attach your scripts modularly
- No inline scripts
Cons:
- Lots of JS files to keep track of
- Lots of HTTP requests to your server
- Each page's JS isn't precached
- No way of passing parameters to the script, everything has to be hard-coded
Inline triggers
A second approach is to have some base library but then activate with some inline script in your page:
<head>
<script src="base.js"></script>
[...]
</head>
<body>
[...]
<script>
doSomeBehaviour('foo', 'bar');
</script>
</body>
Pros:
- One JS that's easily cached
- Triggered functionality per-page
Cons:
- Mixes JS with HTML
POSH triggering
This third approach is one I've preferred to use in the past is to have the Javascript pick up elements that exist in the markup in some sort of POSH form.
<head>
<script src="base.js"></script>
[...]
</head>
<body>
[...]
<div id="foo">
<span class="bar">An element</span>
</div>
</body>
In this instance the base.js would pick up that there's an element with @id="foo" and do some action based on it (or rather, attach some behaviour).
Pros:
- One JS that's easily cached
- JS only applies when needed
Cons:
- Lots of findById() to check every possible element that might trigger a behaviour
- Can only apply after DOM is ready
The Frontal approach - path-based actions
What frontal does quite simply and brilliantly is allow you to specify Javascript that gets run based on the URL of the current script:
$frn('/blog', function(){
// some blog-specific action
});
$frn('/news/latest', function(){
// e.g. script that refreshes the list of news items
});
$frn(/blog\/.*zend.*/, function(){
// action for blog items with Zend in the URL
});
I find this approach really interesting, and would be pretty keen to see how it can be integrated with your average framework's routing mechanism (specifically ZF and the URL view helper).
Pros:
- One big JS
- JS only applied on pages where it's needed
Cons:
- Page-specific JS might not be fine-grained enough
- Need to link to Frontal as a library to use (unless you replicate the pattern)
Looking forward
At first glance I tend to think that a mixed strategy of the Frontal and POSH approaches - I still tend to think that JS should get as much of the 'stuff' it needs to understand from POSH-esque structures within the page (e.g. a Google Map probably shouldn't have it's coordinates hardcoded in the JS). However it does get costly to keep traversing the DOM, and you can't always wait for the DOM to be available, so there's a strong argument for combining that with Frontal and nesting the POSH checking inside Frontal clauses.
I'm going to keep nagging Carl about getting this integrated into a Zend project, and would like to see it bundled into a jQuery plugin.
1.
In nearly all sites, except for the very biggest and the very smallest, I much prefer to have several seperate js files containing code for a specific part of the website or to perform a specific task. The same preference applies to css files too.
For cacheing and http requests this is not ideal but for simplicity, and ease of maintenance I much prefer it.
In situations where a single js file is prefered I could see the value in frontal.
Jquery plugin would be a massive win.
Russell
25th March 2010, 11:25