Using non-AMD compatible javascript module with re

2019-02-01 12:43发布

问题:

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?

回答1:

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



回答2:

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']
    }
  }
);


回答3:

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

    });
});