这是一个更具体的例子。
我正在一个有60个文件的项目中。我们有2种不同的运行方式。
加载一个串联的版本,一个大文件。(生产)
加载全部60个文件(开发)
我们使用的是加载程序,因此网页中只有一个脚本
<script src="loader.js"></script>
默认为模式#1(加载一个大的串联文件)。为了在模式2下运行(单独的文件),我们设置一些标志。可能是任何东西。查询字符串中的键。在此示例中,我们只是这样做
<script>useDebugVersion = true;</script>
<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
等等...
如果添加了新文件,由于我们正在进行开发,我们可能会使用模式#2,因此必须在injectScript("somenewfile.js")
loader.js中添加一行
然后,在以后的生产中,我们还必须向我们的构建脚本中添加somenewfile.js。我们经常忘记这一步,然后得到错误消息。
通过切换到AMD,我们不必编辑2个文件。保持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将为我们注入脚本,并且直到我们加载lib1为止,它才会注入lib2,因为我们告诉过lib2依赖于lib1。在加载了lib2和lib1之前,它也不会启动使用lib1的模块。
这使开发变得更加美观(无需构建步骤,无需担心加载顺序),并使生产变得更加美观(无需为添加的每个脚本更新构建脚本)。
作为额外的好处,我们可以使用webpack的babel插件在旧版浏览器的代码上运行babel,同样,我们也不必维护该构建脚本。
请注意,如果Chrome(我们选择的浏览器)开始支持import
真正的浏览器,我们可能会改用它进行开发,但这并不会真正改变任何东西。我们仍然可以使用webpack来创建一个串联文件,并且可以使用它在所有浏览器的代码上运行babel。
所有这些都是通过不使用脚本标签和使用AMD获得的