RequireJS - What is the purpose of the "exports" property in shim

Requirejs

Requirejs Problem Overview


What is the purpose of the "exports" property in the shim below? Is it really required?

requirejs.config({
    shim: {
        'backbone': {
            deps: ['underscore', 'jquery'],
            exports: 'Backbone'
        }
    }
});

I ask because it seems redundant - when the module is included in a dependency list, we will specify the exported name again as the function argument:

define(['backbone'], function (Backbone) {
  return Backbone.Model.extend({});
});

Requirejs Solutions


Solution 1 - Requirejs

If shim is not used in your example then the Backbone object you pass in as a parameter would be undefined as Backbone is not AMD compliant and does not return an object for RequireJS to use.

define(['backbone'], function (Backbone) {
  // No shim? Then Backbone here is undefined as it may
  // load out of order and you'll get an error when
  // trying to use Model
  return Backbone.Model.extend({});
});

To give a bit of context I will use the code that the r.js optimiser spits out but I will simplify it for this example. It helped me understand the point of it by reading what the optimiser produces.

The shimmed Backbone would be a little like this:

// Create self invoked function with the global 'this'
// passed in. Here it would be window
define("backbone", (function (global) {
	// When user requires the 'backbone' module
	// as a dependency, simply return them window.Backbone
	// so that properites can be accessed
    return function () {
        return global.Backbone;
    };
}(this)));

The point is to give RequireJS something to return back to you when you ask for a module, and it will ensure that is loaded first before doing so. In the case of the optimiser, it will simply embed the library before hand.

Solution 2 - Requirejs

If you don't use "export" Backbone, then you can't get the locale reference in module to Backbone(window.Backbone) which is defined in backbone.js.

//without export Backbone
shim : {
  'bbn':{
        //exports:'Backbone',
        deps:['underscore']
    },
    'underscore': {
        exports: '_'
    }
};


require(['bbn'], function(localBackbone) {
  //localBackbone undefined.
  console.log('localBackbone:,' localBackbone);
});

RequireJs explains as follow:

//RequireJS will use the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
  return Backbone.Model.extend({});
});

RequireJS will use shim config to get global Backbone

function getGlobal(value) {
        if (!value) {
            return value;
        }
        var g = global;
        each(value.split('.'), function (part) {
            g = g[part];
        });
        return g;
    }

Solution 3 - Requirejs

Also note that you might want to use actual export of the plugin in "exports". For example,

requirejs.config({
    shim: {
        'jquery.colorize': {
            deps: ['jquery'],
            exports: 'jQuery.fn.colorize'
        },
        'jquery.scroll': {
            deps: ['jquery'],
            exports: 'jQuery.fn.scroll'
        },
        'backbone.layoutmanager': {
            deps: ['backbone']
            exports: 'Backbone.LayoutManager'
        },
        "jqueryui": {
            deps: ["jquery"],
            //This is because jQueryUI plugin exports many things, we would just 
            //have reference to main jQuery object. RequireJS will make sure to
            //have loaded jqueryui script.
            exports: "jQuery"  
        },
        "jstree": {
            deps: ["jquery", "jqueryui", "jquery.hotkeys", "jquery.cookie"],
            exports: "jQuery.fn.jstree"
        },
        "jquery.hotkeys": {
            deps: ["jquery"],
            exports: "jQuery"  //This plugins don't export object in jQuery.fn
        },
        "jquery.cookie": {
            deps: ["jquery"],
            exports: "jQuery" //This plugins don't export object in jQuery.fn
        }
    }
});

More: https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim

Solution 4 - Requirejs

Shim exports is for letting requirejs know how to handle non-AMD modules. Without it, dependencies in the define block will still be loading, while the module starts. It signals requirejs that it has stopped loading the resource and that modules can start using it.

At least, that's how i see it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNareshView Question on Stackoverflow
Solution 1 - RequirejsSimon SmithView Answer on Stackoverflow
Solution 2 - RequirejsIan JiangView Answer on Stackoverflow
Solution 3 - RequirejsShital ShahView Answer on Stackoverflow
Solution 4 - RequirejsasgothView Answer on Stackoverflow