Posted on by & filed under django, javascript, programming, python.

JavaScript code is becoming an increasingly large part of most web applications, but this often isn’t reflected in server-side web application frameworks. The core Django framework, for example, offers very little explicit support for JavaScript; it’s generally handled as just another type of “static file”, a catchall term for any file needed to render the site which isn’t Python source code or an HTML template.

The problem with this categorization is that modern JavaScript applications look more like traditional compiled software than static images; there’s source code, “compiled” (minified) code, compiler settings, dependency management, and frequent changes in the source that require rebuilding the compiled version. The Django staticfiles framework makes it possible to do all this in a separate deployment process, but that isn’t really ideal. For example, you don’t want to run all of your tests using the JavaScript source files, then discover after deployment that a bug in your minification process broke the compiled JavaScript files in production. The recently released django-require offers one solution to this problem.

Get organized

The first step in getting a handle on this is to organize the JavaScript code itself. The language doesn’t exactly lend itself to this very well, but through herculean effort a few decent solutions have been developed. One of the most popular is the RequireJS library, an Asynchronous Module Definition (AMD) loader. Instead of requiring you to list your scripts in exactly the correct order (sometimes difficult in a template inheritance hierarchy using a large set of JavaScript files) and hoping that none of them use the same global variable in conflicting ways (definitely difficult in a language where it’s actually hard not to accidentally define new global variables), AMD allows you to explicitly list the dependencies for a module of JavaScript code. For example:

define(['first', 'second', 'third'], function (first, second) {
    var exports;
    // My code which depends on first and second goes here
    return exports;

There are a few different ways of writing an AMD module, but this is one of the most common. Basically it lets you use standard JavaScript syntax to define a new module of JavaScript code, which explicitly depends on other such modules (but may not directly need their return values). This example depends on three other modules, but only directly uses code from two of them; the third was needed for some side effect (perhaps on the other modules or on the page DOM). The return value of the module’s function can then in turn be passed on to other modules which depend on it.

The big wins here are that your code’s dependencies are explicitly stated, you don’t need to add anything to the global namespace beyond the define() and require() functions provided by RequireJS, and RequireJS takes care of loading the dependencies when they’re first needed (and not executing the code in the same module twice). Of course, this is part of the core functionality of most other programming languages…

Dependency management

Anyway, you can now build up even a fairly large JavaScript codebase with confidence that you can keep each file to a manageable size and keep all the dependencies straight. But you wouldn’t want to put code like this directly into production; loading potentially dozens of little unoptimized JavaScript files to render a single page is hardly ideal.

To address this problem, RequireJS provides an optimizer called r.js. It analyzes all the dependencies of the main module, packs them into a single file, and uses a minifier on the result. You can even configure it to build multiple different top-level modules (for example, if each page has different scripts) and to break some of the dependencies out into one or more separate files (which can be useful if your scripts on different pages have some big library dependencies in common). If you do collapse all of the scripts on a page into a single file, you can use almond to shrink it even further by using a simpler AMD loader which doesn’t need to be able to dynamically load modules from other files. This lets us compile a version of our JavaScript that we’d be willing to serve in production…but how do we let developers test the compilation process locally to make sure deployments aren’t going to fail?

Enter Django

This is (finally) where django-require comes in. It’s a Django app which provides a mixin for staticfiles storage backends (as well as a couple of such storage classes already configured to use it, for convenience). When Django’s collectstatic management command is run to collect all the static files for deployment, this mixin adds a step which will run r.js in order to generate the optimized version of your JavaScript code. Because it’s integrated with the storage backend, the newly created optimized JS files are handled the same way as the rest of your static files (given a cache-breaking hash suffix when using, uploaded to Amazon S3 if using a subclass of storages.backends.s3boto.S3BotoStorage, etc.) And if you have Selenium or other browser-based tests utilizing LiveServerTestCase, you can just run collectstatic first and your automated tests will use the optimized assets which were generated, allowing you to test the minification process.

The main configuration settings for django-require are managed like any other Django settings; for example, your file might contain:

REQUIRE_JS = os.path.join('src', 'require.js')

For convenience, django-require includes the r.js optimizer itself, almond, the Rhino JavaScript interpreter for Java, a simple default build configuration, and the require.js script (you’ll probably want to copy the latter into your project’s source code as a static file, possibly using the provided require_init management command). Your configuration for r.js (top-level modules, which minifier to use, etc.) goes into an file (as normal for that tool), the location of which is specified using REQUIRE_BUILD_PROFILE as shown above. It also provides a template tag for including your main page script in a template in a way which works both in development with REQUIRE_DEBUG = True and uses the optimized files when REQUIRE_DEBUG = False.

If you have a more complicated setup involving different main scripts for each page (possibly in different directories) with a common script of base dependencies, setting the RequireJS configuration in a single place and having it work across all those scripts in both source and optimized modes can sometimes be a little tricky; I normally put the configuration in its own file (config.js), something like:

  baseUrl: "/static/js",
  paths: {
    jquery: "src/jquery-1.7.1",
    underscore: "src/underscore",
    backbone: "src/backbone",
    text: "src/text"
  shim: {
    "src/chosen.jquery.min": {
      deps: ["jquery"],
      exports: "jQuery.fn.chosen"
    "src/jquery.cookie": {
      deps: ["jquery"],
      exports: "jQuery.cookie"
    "src/jquery.placeholder": {
      deps: ["jquery"],
      exports: "jQuery.fn.placeholder"

This can be specified as the configuration for the optimizer easily enough in

mainConfigFile: "./config.js",

And then your base template can look something like this:

<script src="{% static 'js/src/require.js' %}"></script>
{% if REQUIRE_DEBUG %}<script src="{% static 'js/config.js' %}"></script>{% endif %}
<script>require(["{% script 'js/pages/base.js' %}"], function () {
    {% block page_script %}{% endblock %}

A page which has its own script which depends on base.js would have something like the following in its template:

{% block page_script %}require(["{% static 'js/pages/page1.js' %}"]);{% endblock %}

This ensures that the base script finishes loading before the page-specific ones which depend on it, and that the RequireJS configuration is run first in development mode, before the location of the first script encountered might confuse the issue of what the baseUrl property is to be set to.

Once you have everything configured, you can test the site using the optimized JS files by running the following commands (remember to set DEBUG = False):

./ collectstatic
./ runserver --insecure

Now you can start writing those automated tests I mentioned earlier, to make sure things stay working. For example, you could write some Selenium tests for your Django site, as I described in some earlier posts.


3 Responses to “Optimizing JavaScript in a Django Project: django-require”

  1. Jet Table Saw

    I leave a response whenever I especially enjoy a article on a site or I have something to
    add to the discussion. Usually it is a result of the sincerness
    communicated in the article I browsed. And after this article Optimizing JavaScript in a Django Project:
    django-require | Safari Flow Blog. I was excited enough to drop a thought ;)
    I actually do have some questions for you if it’s
    okay. Is it simply me or do some of these remarks appear like they
    are coming from brain dead individuals? :-P And, if you are writing
    at additional social sites, I’d like to follow anything new you have to post.

    Would you make a list all of all your social pages like your Facebook page, twitter feed, or
    linkedin profile?