backbone

Chaining Backbone Plugins with Require.js

You may have run into this situation.. You are building a backbone application, and you want to take advantage of any number of plugins.. let's say for this example, extended models and caching.. oh, and you also want to override some of backbone's prototypes, because you have some custom needs (my use case - adding pointer.js to the event object to handle click/touch events). Let's also say you are using require.js, because if you aren't using either require or something like browserify, you should be (please don't argue which one is better, for my particular use case, browserify is not an option). In any case, you have a bunch of plugins which extend Backbone, but you don't want to have to attach them all to each of your modules. It would be oh-so-much easier to just be able to do define(['backbone']... since you want access to all of these, everywhere...

Require.js and the shim to the rescue:


require.config({
paths: {
        jquery: '../components/jquery/jquery-2.0.mobile',
        backboneBase: '../components/backbone/backbone',
        underscore: '../components/underscore/underscore',
        backbone: 'plugins/backbone.overrides',
        DeepModel: 'plugins/backbone.deep-model',
        Cache: 'plugins/backbone-fetch-cache',
},
shim:{
        underscore: { exports: '_' },
        backboneBase: {
            deps: ['jquery', 'underscore'],
            exports: 'Backbone'
        },
        backbone:{
          deps:['backboneBase'],
          exports:'Backbone'
        },
        Cache:{
            deps:['backbone'],
            exports: 'Backbone'
        },
        DeepModel: {
            deps: ['Cache', 'underscore', 'plugins/underscore.mixin.deepExtend']
        },
}
});

That's the code.. so what exactly are we doing here?

First, we're setting aliases to all the backbone related script files that we need. Second, we're using shim to load each in the order that we need them to properly set up extension availability. For example, I have a file that overrides the default View.delegateEvents method to convert click events to pointer.js standardized pointer events (so it works for mouse or touch). I want to load this one as the main backbone export, so I call it backbone, and the original, unadulterated backbone is 'backboneBase'.

Next, I want to add the fetch-cache and deepModel plugins. Since I'm already referencing define(['DeepModel'... in my project, I want to make sure Cache is always available with DeepModel, so I load it as a dependency to DeepModel. It exports Backbone with fetchCache attached. If I changed my code to define(['backbone... I would lose both of these extensions.

You can play around with how you want to name/load your extensions in order to provide the module setup that fits your project. I'm sure someone has a better way for me to do this, and I'd love to hear it!