5

我正在创建我的第一个用于开源分发的 AngularJS 模块。我想以一种易于其他人消费的方式包装它。

UMD 项目提供了一种用于导出与 AMD、CommonJS(或至少是 Node)和浏览器全局兼容的 JavaScript 模块的模式:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['b'], factory); // AMD
  } else if (typeof exports === 'object') {
    module.exports = factory(require('b')); // Node
  } else {
    root.returnExports = factory(root.b); // browser global (root is window)
  }
}(this, function (b) {
  // use b in some fashion
  return {}; // return a value to define the module export
}));

但是,由于 AngularJS 有自己的内部模块系统,注册模块只需调用angular对象上的方法即可,即angular.module(). 因此,UMD 模块不需要导出任何东西;它只需要要求并采取行动angular。就前面的示例而言,我认为这看起来像这样:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    factory(require(['b'])); // AMD
  } else if (typeof exports === 'object') {
    factory(require('b')); // Node
  } else {
    factory(root.b); // browser global (root is window)
  }
}(this, function (b) {
  // use b in some fashion
}));

或者,具体到我的情况:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    factory(require(['angular'])); // AMD
  } else if (typeof exports === 'object') {
    factory(require('angular')); // Node
  } else {
    factory(root.angular); // browser global (root is window)
  }
}(this, function (angular) {
  angular.module( ... );
}));

这没什么大不了的,还是违背了UMD的精神?我问是因为我找不到任何不导出任何东西的 UMD 模式。

4

2 回答 2

2

我认为使用这种模式没有任何问题。正如您可能已经发现的那样,Angular 与现有的模块系统配合得不是很好,因为它使用自己的模块系统,但是模块不必导出任何东西。项目的主模块多久导出一次内容?通常它只是获得依赖关系。

如果您正在寻找执行类似操作的示例,您可以查看 jQuery 鼠标滚轮插件,它使用 UMD 但依赖于 jQuery。

摘自jquery.mousewheel.js

(function (factory) {
    if ( typeof define === 'function' && define.amd ) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports = factory;
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {

不同之处在于它为 Node/CommonJS 导出返回了一个构造函数,以便您可以传入您希望扩展的 jQuery 对象。


附带说明一下,在 AMD 部分中,您的 UMD 实现存在一个问题。

你有:

factory(require(['b'])); // AMD

您需要的地方:

define(['b'], factory); // AMD

由于 AMD 是异步的,因此您将无法同步要求 angular 模块。

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['b'], factory); // AMD
  } else if (typeof exports === 'object') {
    factory(require('b')); // Node
  } else {
    factory(root.b); // browser global (root is window)
  }
}(this, function (b) {
  // use b in some fashion
}));
于 2015-12-22T23:19:10.220 回答
1

作为一个角度插件,提供一个导出构建器的模块可能会更好,这样人们就可以对“角度意味着什么”负责。例如,假设我正在使用 angular 的自定义调试版本,但想使用您的代码:现在,我不能,因为您已决定为我需要 angular。这似乎是个好主意,但实际上并非如此:

var myangular = require('debug-angular/ext/symbolised');
var yourmodule = require('yourmodule');
yourmodule.register(myangular);

现在我知道,作为开发人员,您的代码将使用我的Angular,而不是现在加载两个不同版本的 Angular,以及由此产生的所有有趣的版本不匹配错误。

所以一个更好的 umd 工厂应该是这样的:

(function (root, factory) {
  if (typeof define !== 'undefined' && define.amd) {
    define(['angular'] , function (angular) {
      factory(angular);
    });
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
      register: function(angular) {
        factory(angular);
      }
    };
  } else {
    factory(root.angular); // browser global (root is window)
  }
}(this, function (angular) {
  angular.module( ... );
}));
于 2015-12-22T23:03:17.763 回答