Вот более конкретный пример.
Я работаю в проекте с 60 файлами. У нас есть 2 разных режима работы.
Загрузите объединенную версию, 1 большой файл. (Производство)
Загрузить все 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(...);
Но поскольку внедренные скрипты загружаются асинхронно, нет гарантии, что они загрузятся в правильном порядке. Эти 2 сценария не являются сценариями 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.
Это делает разработку удобной (без этапа сборки, не беспокоясь о порядке загрузки) и делает производство приятным (нет необходимости обновлять сценарий сборки для каждого добавленного сценария).
В качестве дополнительного бонуса мы можем использовать плагин babel webpack для запуска babel над кодом для старых браузеров, и, опять же, нам не нужно поддерживать этот сценарий сборки.
Обратите внимание, что если бы Chrome (наш любимый браузер) начал поддерживать import
реальную поддержку, мы, вероятно, переключились бы на него для разработки, но это ничего не изменит. Мы все еще могли бы использовать webpack для создания объединенного файла, и мы могли бы использовать его для запуска babel над кодом для всех браузеров.
Все это достигается за счет отказа от тегов скриптов и использования AMD