django: far future expires and template tags
March 25, 2008 - 6:19 PM
For those of you who haven't read about them, a while back Yahoo released a guide on making your webpages load faster. They even worked with the developer of firebug to make a firefox add-on called YSlow that will load your page and give you feedback on it's performance.
One of the rules discussed it to set what is called a "far future expires" on js and css files. How it works is that you set an expires header so far into the future (usually 10 or more years) that the object itself will be cached essentially forever. Of course this presents a problem. What happens when you update your css or js? Your users won't get the new files which at the very least will make things look funny or at worst break your entire site.
To prevent that from happening at Digg we use urls that look like /js/24/jquery.js and mod_rewrite to redirect them to the proper location on the file system. Anytime changes are made to css or js, we increment the version and the new url is used forcing browsers to download the updated file.
In order to follow the DRY principal and still use this methodology I created a few template tags to make this all easier. The code will insert a version number in the url as well as append the MEDIA_URL from the settings file. Now anytime I update my css, js, or images all I will need to do is update the version in the settings file and the cache is broken and users get the updated file.
The code is a little lengthy to put in a post but so you can see how it works. In my template I do things like this:
{% load media_url %}
<link rel="stylesheet" href="{% css_url "css/style.css" %}" />
<script type="text/javascript" src="{% js_url "js/jquery.js" %}"></script>
Which in turn outputs:
<link rel="stylesheet" href="/media/css/1/style.css" />
<script type="text/javascript" src="/media/js/1/jquery.js"></script>
For a little example of what I am talking about. Performance results from the homepage of my blog:
See the Django snippet for full source.
Side Note: This snippet is #666. Use at your own risk I guess.






