28

我正在将 AMD 支持添加到我开发的 javascript 库中。

该库可能使用 jquery,但如果未加载 jquery,它仍然可以工作。

在定义模块依赖项时,有一种方法可以将依赖项设置为“可选”,这样如果缺少该库,模块仍然可以工作吗?

4

3 回答 3

27

我最近遇到了完全相同的问题,这就是我解决它的方法。我定义了一个名为 RequireJS 的插件optional,它通过将无法加载的模块显式定义为空对象来忽略它们(但我想您也可以将其定义为 null 或其他任何内容)。

这是代码(使用 RequireJS 2.1.15 测试):

define("optional", [], {
    load : function (moduleName, parentRequire, onload, config){

        var onLoadSuccess = function(moduleInstance){
            // Module successfully loaded, call the onload callback so that
            // requirejs can work its internal magic.
            onload(moduleInstance);
        }

        var onLoadFailure = function(err){
            // optional module failed to load.
            var failedId = err.requireModules && err.requireModules[0];
            console.warn("Could not load optional module: " + failedId);

            // Undefine the module to cleanup internal stuff in requireJS
            requirejs.undef(failedId);

            // Now define the module instance as a simple empty object
            // (NOTE: you can return any other value you want here)
            define(failedId, [], function(){return {};});

            // Now require the module make sure that requireJS thinks 
            // that is it loaded. Since we've just defined it, requirejs 
            // will not attempt to download any more script files and
            // will just call the onLoadSuccess handler immediately
            parentRequire([failedId], onLoadSuccess);
        }

        parentRequire([moduleName], onLoadSuccess, onLoadFailure);
    }
});

然后,您可以选择简单地使用一个模块

require(['optional!jquery'], function(jquery){...});

知道如果无法加载 jquery 模块,传递给回调函数的参数将是一个空对象。

于 2014-12-11T12:00:17.613 回答
12

您不能真正将其设置为可选,但您可以使用以下方法捕获错误并卸载模块undef

require(['jquery'], function ($) {
    //Do something with $ here
}, function (err) {
    //The errback, error callback
    //The error has a list of modules that failed
    var failedId = err.requireModules && err.requireModules[0];
    if (failedId === 'jquery') {
        //undef is function only on the global requirejs object.
        //Use it to clear internal knowledge of jQuery. Any modules
        //that were dependent on jQuery and in the middle of loading
        //will not be loaded yet, they will wait until a valid jQuery
        //does load.
        requirejs.undef(failedId);
        ...
     }
});

完整的例子在这里

于 2013-01-04T20:46:09.640 回答
0

为此不需要插件。

这可以在没有 RequireJS 插件的情况下完成。此外,您也可以对 UMD 模块执行此操作。

仅在已经加载时使用 jQuery

其实很简单,使用require.defined,它可以让你测试一个模块是否已经被加载。如果是这样,您require使用 jQuery 并使用它,否则您只需跳过可选部分:

define(['require'], function(require){
  if (require.defined('jquery') {
    var $ = require('jquery');
    $.fn.something = function(){};
  }
});

请注意我们如何添加'require'为依赖项,因此我们得到了一个本地 require 函数,其中包含该defined方法。

另请注意,如果在此模块之前已加载此代码,则此代码只会找到 jQuery 。如果某个模块在该模块已经加载之后加载了 jQuery 那么之后它就不会再加载 jQuery。

这不会尝试加载 jQuery,因此不会导致日志中出现错误消息。

奖励:UMD 支持

如果您希望您的库支持 AMD 加载程序 (RequireJS)、CommonJS (Node) 和常规脚本标签,并且对 jQuery有可选依赖,您可以执行以下操作:

(function(u, m, d) {
    if ((typeof define == 'object') && (define.amd)) {
        // handle AMD loaders such as RequireJS
        define(m, ['require'], d);
    }
    else if (typeof exports === 'object') {
        // handle CommonJS here... Does not really make sense for jQuery but
        // generally, you can check whether a dependency is already loaded
        // just like in RequireJS:
        var $ = null;
        try {
            require.resolve('jquery'));
            // the dependency is already loaded, so we can safely require it
            $ = require('jquery');
        } catch(noJquery) {}
        module.exports = d(null, $);
    }
    else {
        // regular script tags. $ will be available globally if it's loaded
        var $ = typeof jQuery == 'function' ? jQuery : null;
        u[m] = d(null, $);
    }
})(this, 'mymodule', function(require, $) {

    // if `$` is set, we have jQuery... if not, but `require` is set, we may
    // still get it here for AMD loaders
    if (!$ && require && require.defined && require.defined('jquery')) {
        $ = require('jquery');
    }

    // At this point, `$` either points to jQuery, or is null.
});

进一步阅读

Node.js - 检查是否安装了模块而不实际需要它 https://github.com/jrburke/requirejs/issues/856

于 2015-10-11T15:24:33.163 回答