这里有一个更具体的例子。
我正在进行一个包含60个文件的项目。我们有两种不同的运行模式。
加载一个连接的版本,即一个大文件。(生产环境)
加载全部60个文件。(开发环境)
我们使用一个加载器,所以网页中只有一个脚本。
<script src="loader.js"></script>
默认情况下,它会使用模式#1(加载一个大的连接文件)。要在模式#2(分离文件)中运行,我们需要设置一些标志。它可以是任何东西。查询字符串中的一个键。在这个例子中,我们只是这样做
<script>useDebugVersion = true
<script src="loader.js"></script>
loader.js 大致长这样
if (useDebugVersion) {
injectScript("app.js");
injectScript("somelib.js");
injectScript("someotherlib.js");
injectScript("anotherlib.js");
... repeat for 60 files ...
} else {
injectScript("large-concatinated.js");
}
构建脚本只是一个 .sh 文件,看起来像这样。
cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js
如果添加新文件,我们可能会使用mode#2,因为我们正在开发,我们必须将injectScript(“somenewfile.js”)
行添加到loader.js中。
然后,以后在生产中,我们还必须将somenewfile.js添加到我们的构建脚本中。这是我们经常忘记的一步,然后出现错误信息。
通过切换到AMD,我们不必编辑两个文件。保持loader.js和构建脚本同步的问题消失了。使用r.js
或webpack
,它可以只读取代码以构建large-concantinated.js
它还可以处理依赖关系,例如我们加载了2个文件lib1.js和lib2.js。
injectScript("lib1.js");
injectScript("lib2.js");
lib2需要lib1。它内部有类似以下代码的功能
lib1Api.installPlugin(...)
但是由于注入的脚本是异步加载的,所以无法保证它们会按正确顺序加载。这两个脚本不是 AMD 脚本,但是使用 require.js 我们可以告诉它它们的依赖关系。
require.config({
paths: {
lib1: './path/to/lib1',
lib2: './path/to/lib2',
},
shim: {
lib1: {
"exports": 'lib1Api',
},
lib2: {
"deps": ["lib1"],
},
}
});
在我们使用lib1的模块中,我们会这样做
define(['lib1'], function(lib1Api) {
lib1Api.doSomething(...);
});
现在 require.js 将会为我们注入脚本,而且它不会注入 lib2 直到 lib1 被加载,因为我们告诉它 lib2 依赖于 lib1。它也不会启动使用 lib1 的模块直到 lib2 和 lib1 都被加载。
这使得开发过程变得很好(没有构建步骤,不用担心加载顺序),并且使得生产环境变得很好(不需要为每个添加的脚本更新构建脚本)。
额外的好处是,我们可以使用 webpack 的 babel 插件在旧版浏览器上运行 babel,并且我们也不必维护该构建脚本。
请注意,如果 Chrome(我们的选择浏览器)真正开始支持 import,我们可能会转换到该语法进行开发,但这并不会改变任何事情。我们仍然可以使用 webpack 创建一个合并的文件,并且我们可以使用它在所有浏览器上运行 babel。
通过不使用 script 标签和使用 AMD,所有这些都实现了。