RequireJS 历史

Dojo 加载器上做了很多工作。普通的 Dojo 加载器过去使用同步 XMLHttpRequest (XHR) 调用。但是,由于同源策略的限制,XHR 加载器无法从其他域加载 Dojo 模块。所以我创建了 xdomain 加载器,它需要一个构建步骤来注入类似于 RequireJS 使用的函数包装器,但由于 i18n 包加载和 dojo.requireIf 行为,它更加复杂。由于 i18n 和 requireIf 的要求更加复杂,而且世界上已经存在许多 Dojo 模块,我认为 Dojo 社区不会考虑手动编写带有函数包装器的模块。

然而,同步 XHR 加载器还有其他问题,比如使调试更加困难。2009 年,David Mark 建议 Dojo 使用 document.write() 在页面加载之前加载模块,以帮助解决这个问题,但这意味着所需的依赖项将等到当前模块执行后才会加载。如果模块在模块定义中引用了依赖项,这可能会导致错误。所以需要一个函数包装器。Dojo 社区似乎更愿意考虑使用函数包装器,特别是因为我们正在考虑一个可以破坏某些 API 的 Dojo 2.0。我在 dojo-contributors 列表中充实了 RequireJS(当时称为 RunJS)的一些细节,Mike Wilson 最初主张使用更通用的加载器,它可以加载普通文件并允许不同的上下文。

YUI 3 的 use() 函数也与 require 非常相似,use() 的 API(但不是代码)也影响了 RequireJS 的结构。我认为 RequireJS 更通用,因为 YUI 似乎为其模块使用了与文件路径不直接对应的标签。我还喜欢将依赖模块作为参数显式传递给函数定义,因为它允许 JSLint 等代码检查工具更有效。

我最初想要的是可以与 CommonJS 模块一起使用的东西,但这些模块的结构似乎假设了一个同步模块加载器,这在服务器端 JavaScript 环境中是可能的。但是,我主要关心的是在浏览器中运行良好的东西,这意味着需要一个函数包装器,以便我们可以使用脚本标签。使用同步 XHR 对新开发人员或希望跨浏览器轻松调试的人来说不是很友好。它也可能比普通的脚本标签加载慢。某些环境(如 Adobe AIR)不允许使用 eval(),并且大多数开发人员都被教导 eval() 是邪恶的,应该避免使用。

我创建了 RequireJS 的种子,称为 RunJS。当我试图与 CommonJS 模块更加同步以允许更多代码重用时,我提出了CommonJS Transport/C 提案。传输格式允许将传统的 CommonJS 模块映射到最适合浏览器的格式。然后,我将 RunJS 代码转换为 RequireJS,以匹配 Transport/C 提案中的 API。

在实现传输格式的过程中,越来越清楚的是,CommonJS 模块允许使用命令式 require(),这在 Web 上很尴尬。许多情况在 Web 上下文中不起作用,更好的解决方案是允许在这些情况下使用基于回调的 require。但是,CommonJS 列表中的一些参与者希望即使在回调样式的 require 中也保留命令式使用,这使得该 API 比它应该的更加冗长。

对 Transport/C 提案进行了一些调整,Kris Zyp 想出了如何让匿名模块在该格式中工作。在那时,Kris 觉得它可以作为一个模块 API 提案,而不仅仅是一个传输格式,他在 CommonJS wiki 上创建了一个异步模块定义 (AMD) API 的提案。在讨论该 API 的过程中,Tom Robinson 建议使用 Function.prototype.toString() 来扫描工厂函数的依赖项,尽管 Tom 本身并不关心 AMD API。toString() 扫描作为简化的 CommonJS 包装被纳入 AMD API 中,因为并非所有 JS 环境都支持可用的 toString() 值。

CommonJS 列表中的一些参与者认为 AMD API 提案不符合最初的 CommonJS 模块目标,因为它没有在 CommonJS 模块中保留完整的命令式 require() 风格。他们还认为该提案是在列表中突然提出的,并且实施和推广不当,尽管在我看来,它被标记为一个提案,并且还有其他人也在谈论他们对其他 CommonJS 提案的实施。

沟通上的障碍如此之大,以至于难以继续在 CommonJS 列表中讨论 AMD。然而,我们有足够多的 Web 开发人员仍然认为它有价值,并且在加载器插件和回调 require 周围还有一些 API 工作要做,因此创建了 amd-implement 电子邮件列表和 amdjs Github 小组来继续这些讨论。

通过 amd-implement 列表,回调 require 和加载器插件 API 获得了更多定义和一组单元测试。更多 AMD 实现被创建出来。Dojo 已经处于使用 AMD 的代码转换过程中,而 MooTools 和 EmbedJS 等其他人也采用了它。AMD 加载器在那些想要模块化 JS 加载功能的 jQuery 社区中获得了关注。

AMD 现在拥有一个健康的生态系统。我继续通过在 RequireJS 中提供可靠的实现来帮助推动 AMD 的发展,并确保它非常适合 Web。