Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using non-AMD compatible javascript module with require.js?

I'm using require.js to help organize my Backbone.js based application.

I'm trying to figure out the right way to use a 3rd party javascript library that is not AMD compatible with require.js

The library in questions is backbone-tastypie.js. Basically what the library does is monkeypatch some of the prototype methods of Backbone to provide simpler support for the TastyPie Django REST framework. It does this by directly manipulating the Backbone object in the global namespace.

However, since I'm using Backbone.js as a require.js module, it isn't available when this library tries to access it.

How can I go about importing this backbone-tastypie in the scope of Backbone?

like image 874
erikcw Avatar asked Dec 30 '11 03:12

erikcw


People also ask

Can I use require in JavaScript?

“Require” is built-in with NodeJS With require , you can include them in your JavaScript files and use their functions and variables. However, if you are using require to get local modules, first you need to export them using module.

Is RequireJS outdated?

Yes, it is still used a lot.

What is AMD require?

AMD provides some CommonJS interoperability. It allows for using a similar exports and require() interface in the code, although its own define() interface is more basal and preferred. The AMD specification is implemented by Dojo Toolkit, RequireJS, and other libraries.


2 Answers

UPDATE: I have forked an AMD compatible backbone-tastypie called backbone-tastypie-amd.

While sander's solution would work, its a little annoying to do the whole nested require thing every time you want backbone.

backbone-tastypie is what is called a "traditional script". You can solve the issue in 4 ways.

  1. Make backbone-tastypie AMD compatible yourself. You can do this in one of two ways. Option 1 would be to never include backbone directly - only backbone-tastypie. Then modify backbone tastypie to ensure backbone is required.

    var root = this;
    var Backbone = root.Backbone;
    if (!Backbone && (typeof require !== 'undefined')) Backbone = require('backbone').Backbone;
    

    However this isn't very nice because essentially it will start downloading backbone after backbone-tastypie has loaded (synchronous). It also doesn't give requirejs the full understanding of how these modules relate, and thats the point right? So lets wrap backbone-tastypie in a define():

    (function (factory) {
            if (typeof define === 'function' && define.amd) {
                    // AMD. Register as an anonymous module.
                    define(['backbone'], factory);
            } else {
                    // RequireJS isn't being used. Assume backbone is loaded in <script> tags
                    factory(Backbone);
            }
    }(function (Backbone) {
            //Backbone-tastypie contents
    }));
    

    This is by far the best option out of everything in this answer. RequireJS knows about the dependencies and it can resolve them, download them and evaluate them correctly. It's worth noting that Backbone itself loads underscore using option 1 and does not define itself as a module, which is pretty bad. You can get the AMD optimised version of backbone right here. Assuming you are using this AMD version you can now go right ahead and require backbone-tastypie in your app (either by requiring it in a define() or the actual require() function). You dont have to include backbone or underscore either, as those dependencies are resolved by requirejs.

  2. Use the require.js ordering plugin. This forces things to load in order (still asynchronous in some respects as it downloads them whenever, but evaluates in correct order)

    require(["order!backbone.js", "order!backbone-tastypie.js"], function () {
         //Your code
    });
    
  3. Put backbone.js in the priority config. This forces backbone and its dependencies to always load first no matter what.

  4. Append backbone-tastypie to the same file as backbone.js. Every time backbone is loaded, so is backbone tastypie. Hacky? Yes. But this is very similar to the recommended way of using jquery with requireJS (jquery plugins need jquery to be loaded - much like backbone-tastypie needs backbone to be loaded).

like image 163
Adam Thomas Avatar answered Oct 04 '22 13:10

Adam Thomas


The following should work with RequireJS 2.1.0+ assuming you've set up the paths correctly.

require.config({
  shim: {
    'underscore': {
      exports: '_'
    },
    'backbone': {
      deps: ['underscore','jquery'],
      exports: 'Backbone'
    },
    'backbone-tastypie': {
      deps: ['backbone']
    }
  }
);
like image 22
mike.pj Avatar answered Oct 04 '22 14:10

mike.pj