Thursday, January 29, 2009

Announcing django-media-bundler

Just a couple of days ago, I looked at the Net tab in Firebug while doing a full refresh of an audio-enclave page. Here's what I saw on our (needlessly) most javascript heavy page:



As you can see, with all those external files, we were flagrantly violating three of the Yahoo best practices: minimize HTTP requests, put scripts at the bottom, and minify JavaScript and CSS. Obviously, what we wanted was to keep developing our JavaScript just as we had in separate modules, and add a build step to our deploy to concatenate and minify our JavaScript and CSS. We had heard of Rails' Asset Packager plugin, so we looked for a Django plugin that did basically the same thing. We were unable to find one, so we wrote our own, dubbing it django-media-bundler, and threw it up on GitHub. Here are the Firebug results of enabling bundling, minification, and deferred JavaScript on that page:



Using django-media-bundler

The media-bundler is a reusable app, so to install it all you have to do is download the source and add it to INSTALLED_APPS. Describe the JavaScript and CSS bundles you would like to create in settings.py as explained in the media_bundle.default_settings module. By default, deferring is enabled, and bundling is disabled when settings.DEBUG is True to assist debugging. You can override those values in your settings module.

To source your scripts, instead of writing
<script type="text/javascript" src="/url/myscript.js"></script>
<link rel="stylesheet" type="text/css" href="/url/mystyle.css"/>
you put {% load bundler_tags %} at the top of your template and write
{% javascript "js_bundle_name" "myscript.js" %}

{% css "css_bundle_name" "mystyle.css" %}

At the bottom of your page in your base template you should put
{% deferred_content %}
where-ever you want to load the scripts in production. We recommend putting a second section after your body.

And that's it! As a future goal, we'd like to help automate the horizontal spriting of PNG icons. We would have a {% sprite "sprite_bundle" "icon_name.png" %} tag that automatically generates a div with a background and offset. Alternatively, it might be nice to run the script and CSS files through the template preprocessor to allow them to access the urlresolver so we don't have anymore hardcoded URLs or janky inline template JavaScript. Happy hacking!