我需要重新构建现有的 AMD 模块,以使其在有/没有出现 RequireJS 的页面中都可用。我应该怎么做,有没有示例代码?最好是一种不污染全局命名空间的方法,尽管不是严格要求。
6 回答
这根本不是一个坏主意,通常需要 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
});
唯一的缺点是您不能请求其他依赖项,因此这仅在独立库中有用,如下所示
我最近写了一篇关于这个主题的要点,所以我在下面为你复制了相关的部分;但是,请随时查看原始 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;
});
查看UMD。您应该在那里找到适合您目的的模式。模板有些难看,但可以工作。
我认为这是一个非常糟糕的主意。
您必须采取的可能步骤以确保其有效:
- 确保所有模块的依赖项都加载到该页面上(jQuery、Backbone 等)
- 按照您知道它们应该执行的顺序在页面上包含您的模块
- 确保作为另一个模块的依赖项的任何模块创建一个与“导入”模块期望并在其代码中引用的同名的全局变量
- 确保您的模块以相同的名称引用依赖项(包括其他模块)
- 覆盖/创建一个
define
执行模块工厂函数的全局方法
这只是你必须做的一部分。您需要为您的 RequireJS 页面(或至少在其配置中)兼容 AMD 的第三方shim
,但对于您的非 RequireJS 页面也应该是全局的?
简而言之,IMO,将现有代码返工为 AMD 版本会更容易,这可以使您的模块成为非 AMD
根据 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;
};
希望它会帮助某人。
查看Browserify,它将创建一个独立的 .js 文件,其中包含从您的 AMD/JS 代码中嵌入的所有依赖项。
然后,您可以发布 2 个版本的代码,一个用于 AMD 用户,一个用于“oldschool” js 用户。