RequireJS - "exports"属性在shim中的作用是什么?

50

以下 shim 中的 "exports" 属性有什么作用?它是否真正必需?

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

我问这个问题是因为它似乎是多余的——当模块被包含在依赖列表中时,我们将再次指定导出的名称作为函数参数:

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

36
如果在您的示例中未使用shim,则作为参数传递的Backbone对象将未定义,因为Backbone不符合AMD规范并且不返回RequireJS可用的对象。
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({});
});

为了提供一些背景,我将使用r.js优化器生成的代码,但我会为这个例子简化它。通过阅读优化器生成的代码,我理解了其用途。

被包装的Backbone代码可能是这样的:

// 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)));

重点是在你请求一个模块时,为RequireJS提供一个返回给你的东西,并确保先加载它,然后再返回。在优化器的情况下,它将在手头嵌入该库。


23
谢谢Simon。我不是在问为什么要使用shim,而是为什么在shim中需要“exports”属性?但是,你的答案给了我一个提示,即“exports”用于识别非AMD模块引入的全局变量。现在我再次阅读文档,他们说:“一旦加载,将全局的'Backbone'用作模块值”。在这个函数参数中使用“Backbone”只是为了给此模块提供本地引用。 - Naresh
1
还有一个需要补充的点,有时候在本地引用全局变量非常重要,例如,在同一页中加载多个版本的同一库时。例如,如果您正在编写依赖于特定版本Knockout的插件,则可能不想使用全局的ko变量,而只是传递到回调函数中的本地变量。 - Ken Smith
至少Backbone.js 1.3.3符合AMD规范。 - Legends

30
如果你没有使用"export" Backbone,那么你就无法在模块中获取对于backbone.js定义的Backbone(window.Backbone)的本地引用。
//without export Backbone
shim : {
  'bbn':{
        //exports:'Backbone',
        deps:['underscore']
    },
    'underscore': {
        exports: '_'
    }
};


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

RequireJs 的解释如下:

//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将使用shim配置来获取全局的Backbone

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

7
被接受的答案甚至没有回答问题!@Ian Jiang的答案更好! - Mark

2
请注意,您可能需要在“exports”中使用插件的实际导出。例如:
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
        }
    }
});

更多内容请查看:https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim

1

Shim导出是为了让requirejs知道如何处理非AMD模块。如果没有它,在定义块中的依赖项仍将在加载,而模块开始运行。它向requirejs发出信号,表明它已停止加载资源,模块可以开始使用它。

至少,这就是我看到的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接