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

3

14

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?

Photography answered 30/12, 2011 at 3:26 Comment(0)
G
12

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).

Gittel answered 31/12, 2011 at 17:44 Comment(0)
T
9

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']
    }
  }
);
Talavera answered 21/2, 2013 at 3:13 Comment(0)
M
2

you can wrap your require with another require the plugin will be loaded first, and afterwards you can do your app.

require(["myCustomTastyPiePlugin.js"], function () {
    //This callback is called after the one script finish loading.

    require(["one.js", "two.js", "three.js"], function () {
        //This callback is called after the three scripts finish loading.

        // all your code goes here...

    });
});
Musgrove answered 30/12, 2011 at 10:27 Comment(4)
I'm still learning AMD, but would it be possible to put this nested require statement in a separate script, and return the appropriate objects combined as members of a composite object? If that would work then you'd only need to require one file whenever you need both.Metachromatism
you can do so yes, you can add them in 1 require block, using the order plugin, to make sure they load in the correct order. Afterwards you can return them as 2 properties of the 1 new module you created. Like in my exmaple, you could return the result of one.js, two.js and three.js as properties of a new module. return {one: one, two: two};Musgrove
The .js extension isn't required with RequireDatha
it's not required but it doensn't hurt to use it either. for beginners it is more obvious in what it actually does.Musgrove

© 2022 - 2024 — McMap. All rights reserved.