Integrating JointJS with RequireJS

Some people ask how to integrate JointJS with the RequireJS module loader. This tutorial describes how to do just that. Starting from JointJS v0.9, it is actually pretty simple. Even though JointJS is not in the AMD format (with the exception of the standalone Geometry and Vectorizer libraries), it is easy to define a shim for it. JointJS exports only one global variable joint.

index.html

Let's start with our index.html file. This file includes only the require.js library, our stylesheets and defines what is the starting point of our application (in our case, main.js file):


<!DOCTYPE html>
<html>
  <head>
      <link rel="stylesheet" href="joint.css" />
  </head>
  <body>
      <div id="app"></div>
      <script data-main="main" src="require.js"></script>
  </body>
</html>
For simplicity, we assume all the files are in the same folder as our index.html file.

RequireJS config, the main.js file

Now we can start with the more interesting part, our main.js file, containing the configuration of our modules needed by RequireJS. JointJS is dependent on jQuery, Backbone (which further depends on Underscore*) and two other libraries developed internally for JointJS, the Vectorizer and Geometry libraries.

First we define our module names and tell RequireJS where to find them (the paths object). Notice how we include JointJS using the joint.clean.js distribution file. This file contains JointJS library less of jQuery, Backbone, Lodash, Vectorizer and Geometry. You can download this file from the Download page.

Next we create our shims that tell RequireJS what to do with libraries that are not AMD compliant. This is defined in the shim section of the RequireJS config where we list dependencies for each of these modules and define what globals our shimed modules export.


require.config({
    paths: {
        geometry: './geometry',
        vectorizer: './vectorizer',
        jquery: './jquery',        
        lodash: './lodash',
        backbone: './backbone',
        joint: './joint.clean'
    },
    shim: {
        backbone: {
            //These script dependencies should be loaded before loading backbone.js.
            deps: ['lodash', 'jquery'],
            //Once loaded, use the global 'Backbone' as the module value.
            exports: 'Backbone'
        },
        joint: {
            deps: ['geometry', 'vectorizer', 'jquery', 'lodash', 'backbone'],
            exports: 'joint',
            init: function(geometry, vectorizer) {
                // JointJS must export geometry and vectorizer otheriwse
                // they won't be exported due to the AMD nature of those libs and
                // so JointJS would be missing them.
                this.g = geometry;
                this.V = vectorizer;
            }
        },
        lodash: {
            exports: '_'
        }
    }
});

// Now we're ready to require JointJS and write our application code.
require(['joint'], function(joint) {
    var graph = new joint.dia.Graph;
    var paper = new joint.dia.Paper({ width: 600, height: 400, model: graph });

    var elApp = document.getElementById('app');
    elApp.appendChild(paper.el);

    var rect = new joint.shapes.basic.Rect({
        position: { x: 50, y: 50 },
        size: { width: 100, height: 100 }
    });
    graph.addCell(rect);
});

* Note we previously mentioned that Backbone is dependent on Underscore but we actually use the Lodash library instead. This is becausae Lodash library is a drop-in replacement for Underscore extending it with more features that JointJS uses.