Facebook Connect and... Best Practices?

This script should be referenced in the BODY of your file, not in the HEAD.

So says the Facebook Connect documentation of its FeatureLoader file. In the... Body? Why?

Turns out, I'm a fan of keeping assets in the head and the.. Er... Body of the page in the body. Go figure. For now, I stuck the file in the head, and it worked. It probably breaks in IE or something, at which point it will be time for plan B. But there was more in store:

<script
src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"
type="text/javascript"></script>

<fb:login-button></fb:login-button>

<script type="text/javascript"> FB.init("YOUR_API_KEY_HERE",
"xd_receiver.htm");
</script>

Oh yeah. Drop that JS directly into that HTML, baby. That's the way it's done. Er... Only not.

No matter, I wrapped that call in a jQuery event for running when the DOM is loaded. Slightly late, admittedly, and it does cause some slight flashes, but dammit if it isn't in a better place. What's that I hear? The user experience is degraded? Unfortunately, that qualifies as `true'. I'll blog again when I've figured out a solution (probably forcing the size of the fbc button's container using CSS so that there'll be no jumping when that sucker's loaded).

In the meantime, I'll go off on a limb and mention that one of the YSlow recommendations is to shove script loading at the bottom of the body tag (http://developer.yahoo.com/performance/rules.html#js_bottom). The point they make is fair, but the trouble is that, once again, performance best practices are overriding coding best practices.

Still, this is slightly more acceptable -- if they're all at the bottom, they're still all in the same place. But not with all the other assets. I'm thinking there are a couple of paths to take:
  • Have a couple of JS files at the top, the second of which writes all of the JS includes into the page post-load. Kind of annoying, of course.
  • Have them at the top, but as part of the deployment process, move those suckers to the bottom of the page through some regex or parsing fun. Now we're talking.
I'm heavily considering changing my headerize plugin to optionally allow the developer to mark a place where they want their scripts to be dropped in at production-time. This would let the developer place them in the `regular' place during development and at the bottom of a page in production for performance purposes. Double-plus bonus: the script includes are always together.

Interestingly enough, the headerize plugin allows you to have all of your scripts in the same place in the outputted page, but facilitates scattering of the script includes over various files in the ERB or HAML versions of the pages (i.e., the ones that are actually edited). Why, then, is this useful? Doesn't it scatter the scripts more that way?

When I say all the scripts should be in the same place, I mean that when I look at a page's source from the browser, I should be able to see, at a glance, all the scripts that are included there (ditto for the stylesheets). When I'm developing, on the other hand, it's much easier to have the script included in the view, partial, or layout that actually needs it, since this creates a more logical grouping. Some might argue that this requires separate layouts, but that seems like overkill for something that isn't really a separate layout, just some extra behavior.

So, my point is: scripts should be together. Ideally, they should be in the page head. Alternatively, if needed for performance, they can be at the bottom. The perfect solution is one that lets you switch between them depending on whether you're in production or not. Too complicated, you might be thinking? Eh, call me a purist who understands pragmatism. The purism tells me to put the scripts in the head. The pragmatism tells me to allow for putting them in the body.

In the end, I think scripts-at-the-bottom is, like most things, something you shouldn't do until you see a clear benefit. And there are other solutions to try first, like compressing all of the scripts into one file (which eliminates most of the parallel-download problem; this is also something that headerize does not support at all yet). Ideally, something like headerize which also combines files into cached compressed single files would, I think, be perfect. And there I have my next task presented to me.