10

我需要重新构建现有的 AMD 模块,以使其在有/没有出现 RequireJS 的页面中都可用。我应该怎么做,有没有示例代码?最好是一种不污染全局命名空间的方法,尽管不是严格要求。

4

6 回答 6

8

这根本不是一个坏主意,通常需要 JS 库来支持 AMD/非 AMD 环境。这是解决方案的一种变体:

!function (name, definition) {
    if (typeof module != 'undefined') module.exports = definition()
    else if (typeof define == 'function' && define.amd) define(name, definition)
    else this[name] = definition()
}('reqwest', function () {

    // Module here

});

唯一的缺点是您不能请求其他依赖项,因此这仅在独立库中有用,如下所示

于 2012-09-25T12:17:54.690 回答
3

我最近写了一篇关于这个主题的要点,所以我在下面为你复制了相关的部分;但是,请随时查看原始 Gist以获取更多信息。

以下样板允许您编写一次模块并使其在 CJS/NodeJs、AMD 或浏览器全局环境中工作。

最佳使用时...

  • 您正在从命名空间(错误、全局)代码迁移到 AMD 或 CJS 模块或两者。
  • 您还不能考虑浏览器全局变量,但还需要通过 NodeJS 测试您的代码(例如Mocha

好处与权衡

  • 一种单一的模块格式,允许您以 AMD、CJS/NodeJS 和旧版浏览器全局变量(如window.*.
  • 允许定义多个依赖项。
  • 通过 CLI/NodeJS 运行器(例如 Mocha)运行单元测试。
  • 在逐步迁移到 CJS/NodeJS 或 AMD 模块时减轻痛苦。
  • 你放弃了类似 Java 的命名空间(例如 com.company.package.module)——嗯,反正它们是一团糟。
  • 这(UMD)不是标准;公平地说,AMD 也不是(这是一个具有明确规范的约定)。
  • 大量的样板(和丑陋的)。

例子

/**
 * Creates a an "AppWidget" module that imports a "SingleDependency" constructor and exposes an "AppWidget" constructor.
 * 
 * Allows you to access AppWidget as a CJS/AMD module (i.e. NodeJS or RequireJs):
 * 
 * @example
 *    var AppWidget = require('app-widget')
 * 
 * Allows you to access AppWidget as a legacy browser global:
 * 
 * @example
 *    var AppWidget = window.AppWidget
 */

!(function (name, context, definition) {
  if (typeof exports === 'object') { module.exports = definition(require); } else if (typeof define === 'function' && define.amd) { define(definition); } else { context[name] = definition(); }
}).call(this, 'AppWidget', this, function (require) {
  'use strict'

  // imports
  var SingleDependency = (typeof require === 'function') ? require('./single-dependency') : window.SingleDependency;
  var singleDependency = new SingleDependency();

  function AppWidget() {}
  AppWidget.prototype.start = function () {};

  // exports
  return AppWidget;

});
于 2013-01-08T07:55:41.243 回答
1

查看UMD。您应该在那里找到适合您目的的模式。模板有些难看,但可以工作。

于 2012-09-25T12:22:29.953 回答
0

我认为这是一个非常糟糕的主意。

您必须采取的可能步骤以确保其有效:

  1. 确保所有模块的依赖项都加载到该页面上(jQuery、Backbone 等)
  2. 按照您知道它们应该执行的顺序在页面上包含您的模块
  3. 确保作为另一个模块的依赖项的任何模块创建一个与“导入”模块期望并在其代码中引用的同名的全局变量
  4. 确保您的模块以相同的名称引用依赖项(包括其他模块)
  5. 覆盖/创建一个define执行模块工厂函数的全局方法

这只是你必须做的一部分。您需要为您的 RequireJS 页面(或至少在其配置中)兼容 AMD 的第三方shim,但对于您的非 RequireJS 页面也应该是全局的?

简而言之,IMO,将现有代码返工为 AMD 版本会更容易,这可以使您的模块成为非 AMD

于 2012-09-24T06:16:49.453 回答
0

根据 Simon Smiths 的回答,我处理了模块依赖项:

(function (root, factory) {
    if (typeof exports === "object") {
        module.exports = factory();
    } else if (typeof define === "function" && define.amd) {
        define(['jquery', 'ol'], factory);
    } else {
        root.module_name = factory();
    }
}(this, function (_$, _ol) {
    return new function () {
        // supposed that window.ol and window.$ are defined
        var ol = goog.isDef(_ol) ? _ol : window.ol;
        var $ = goog.isDef(_$) ? _$ : window.$;
}
}));

goog.isDef函数在哪里Google Closure

goog.isDef = function(val) {

  return val !== void 0;
};

希望它会帮助某人。

于 2015-07-13T15:21:38.557 回答
-1

查看Browserify,它将创建一个独立的 .js 文件,其中包含从您的 AMD/JS 代码中嵌入的所有依赖项。

然后,您可以发布 2 个版本的代码,一个用于 AMD 用户,一个用于“oldschool” js 用户。

于 2014-12-19T17:14:31.287 回答