顺应浏览器的工作方式§ 1

XMLHttpRequest (XHR) 加载器只能访问与页面同域的资源,并且会增加调试难度。某些浏览器允许使用 eval 进行跨域 XHR 调用和更好的调试约定,但浏览器之间的支持不一致。

应避免使用基于 eval 的加载器,因为 eval 不是 JavaScript 的最佳实践,而且在某些环境中不允许使用 eval。虽然 eval 有其适用的场景和时机,但模块加载器可以做得比使用 eval 更好。

不应需要通过服务器进程动态转换脚本。让所有人都使用相同的服务器进程,甚至为通用格式制定规范,都会带来额外的开销,需要编写更多的内容。前端开发者长期以来已形成一个成熟的做法,即直接编写纯文本文件,并使其无需大量服务器硬件就可以加载到浏览器中。

通过 script 标签加载的脚本适用于所有环境并支持跨域。这是一种更简单的加载方式,利用浏览器加载脚本的自然机制。

在页面加载前后加载代码§ 2

同一系统应在页面加载前后均可使用。将代码加载延迟到后续页面操作是提升性能的重要手段。

脚本应能指定依赖关系§ 3

项目很容易超出只使用几个脚本的需求。手动追踪所有依赖关系及其正确的加载顺序是非常困难的。一个脚本应能够指定其直接依赖关系。开发者不应担心这些依赖项本身的依赖需求以及正确的加载顺序。

加载器应能加载嵌套依赖关系§ 4

如果每个模块都指定了它自己的直接依赖项,加载器应该能够处理整个系统中的正确依赖关系,包括嵌套依赖(也就是依赖项的依赖项)。

脚本可能以无序的方式执行,但模块必须按照依赖关系执行§ 5

使用具有嵌套依赖解析能力并且能在页面加载后工作的浏览器原生脚本加载机制意味着至少部分时间需要通过 appendChild 方法添加 script 元素来加载脚本。

IE 和 WebKit 浏览器会按照网络接收顺序执行通过 appendChild 添加的脚本,而不是 DOM 顺序。即使它们按照添加到 DOM 的顺序执行脚本,在模块脚本加载完成后才会发现该模块的依赖项,因此这些依赖项的脚本总是会在需要用到它们的脚本之后才被添加。

这导致了我们需要构造一种脚本的模块格式,把脚本的主要内容放在一个函数中,而将其依赖关系的定义放在该函数包装之外。这允许浏览器以任意顺序加载并执行脚本,但提供了机会正确解析依赖关系,然后按正确的顺序调用函数包装器,使脚本得以正确运行。

模块格式应简洁§ 6

冗余代码是一种负担。然而,为了实现上述功能,样板代码中的一部分需要包含一个函数包装器。尽量让样板代码尽可能简洁明了,以便开发者方便手动编码。避免使用每个属性都显式地以名/值对形式表示的模块格式,因为这些都需要开发者手动编写。

核心加载器要简洁,但具备可扩展性§ 7

加载器的核心(支持嵌套依赖解析的模块格式)应当简洁紧凑,但也要支持通过插件扩展依赖的理解和加载方式。

在 Dojo 中,通常需要国际化字符串包和用于小部件构建的 HTML 文本字符串。允许通过插件加载这些东西,同时保持核心轻量。

允许模块保持干净的全局命名空间§ 8

随着项目规模的扩大,页面中需要加载两个版本的同一模块的情况会越来越常见。应允许模块系统不在全局命名空间中定义模块,从而解决这个问题。

如果模块希望使用全局命名空间,这在模块规范中通常很容易实现。更难的部分是构造一种格式,使其能够在不污染全局命名空间的情况下良好工作。

加载任何脚本§ 9

并非所有脚本都会采用模块格式。应允许加载现有的脚本并将其视为依赖项。

支持性能优化升级§ 10

这主要意味着需要一个构建系统,能够合并和优化模块。这也意味着加载器应允许加载包含多个模块定义的脚本文件,并仅获取未包含在该脚本文件中的依赖项。