【问题标题】:requireJS optional dependencyrequireJS 可选依赖
【发布时间】:2012-12-19 07:58:39
【问题描述】:

我正在向我开发的 JavaScript 库添加 AMD 支持。

这个库可以使用 jquery,但如果没有加载 jquery,它仍然可以工作。

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

【问题讨论】:

    标签: javascript requirejs amd


    【解决方案1】:

    您不能真正将其设置为可选,但您可以使用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);
            ...
         }
    });
    

    完整示例here

    【讨论】:

    • 这不会阻止任何依赖于失败模块的模块加载吗?
    • 这不是要走的路,因为这实际上会尝试加载 jQuery。这也是为什么您无法通过这种方式避免控制台中的错误的原因。但是,只有当 jQuery 已经可用时,您才能加载它。请参阅下面的答案。
    • @StijndeWitt 这不是预期的行为吗?如果一个模块没有被加载,并且你有使用该模块的代码,那么即使它是可选的,也不能尝试获取该模块?
    • 在我的书中,自己加载 jQuery 的脚本表现不佳。如果 jQuery 是一个可选依赖项,在我的书中这意味着它会在 jQuery 存在时使用它,仅此而已。但显然有些人对此感到满意......我想知道他们中有多少人设计了快速加载的网站。
    【解决方案2】:

    不需要插件。

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

    仅在已加载的情况下使用 jQuery

    ​​>

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

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

    注意我们如何将'require' 添加为依赖项,因此我们获得了一个具有defined 方法的本地require 函数。

    另外请注意,此代码只有在 在此模块之前加载时才能找到 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 - check if module is installed without actually requiring it https://github.com/jrburke/requirejs/issues/856

    【讨论】:

      【解决方案3】:

      我最近遇到了完全相同的问题,下面是我解决它的方法。我定义了一个名为 optional 的 RequireJS 插件,它通过将无法加载的模块显式定义为空对象来忽略它们(但我想您也可以将其定义为 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 模块,则传递给回调函数的参数将是一个空对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-19
        • 2013-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多