Требовать: связывать или не связывать

Я использую RequireJS для своего веб-приложения. Я использую EmberJS для рамки приложения. Я пришел к выводу, что, как мне кажется, я должен начать связывать свое приложение с одним файлом js. Вот где я немного запутался:

Если я, наконец, собираю все в один файл для развертывания, то все мое приложение загружается одним выстрелом, а не по требованию. Разве это не связывание, противоречащее AMD вообще и RequireJS в частности?

Что еще меня смущает, это то, что я нашел на веб-сайте RequireJS:

Как только вы закончите разработку и хотите развернуть свой код для своих конечных пользователей, вы можете использовать оптимизатор для объединения файлов JavaScript вместе и его минимизации. В приведенном выше примере он может комбинировать main.js и helper/util.js в один файл и минимизировать результат.

Я нашел этот похожий поток, но он не отвечает на мой вопрос.

Ответ 1

Если я, наконец, собираю все в один файл для развертывания, то все мое приложение загружается одним выстрелом, а не по требованию. Разве это не связывание, противоречащее AMD вообще и RequireJS в частности?

Это не противоречиво. Загрузка модулей по требованию является лишь одним из преимуществ RequireJS. В моей книге большая польза заключается в том, что модуляция помогает использовать подход "разделяй и властвуй". Мы можем посмотреть на это следующим образом: несмотря на то, что все функции и классы, которые мы помещаем в один файл, не пользуются загрузкой по требованию, мы по-прежнему пишем несколько функций и несколько классов, потому что это помогает разбивать проблему структурированным способом.

Однако множественность модулей, которые мы создаем в разработке, не обязательно имеет смысл при запуске приложения в браузере. Наибольшая стоимость загрузки по требованию отправляет несколько HTTP-запросов по проводу. Скажем, ваше приложение имеет 10 модулей, и вы отправляете 10 запросов для его загрузки, потому что вы загружаете эти модули по отдельности. Ваша общая стоимость будет той стоимостью, которую вы должны заплатить, чтобы загрузить байты из 10 файлов (позвоните по адресу Pc для стоимости полезной нагрузки), плюс накладные расходы для каждого HTTP-запроса (позвоните в Oc для накладных расходов). Накладные расходы связаны с данными и вычислениями, которые должны произойти, чтобы инициировать и закрывать эти запросы. Они не несущественны. Таким образом, вы платите Pc + 10 * Oc. Если вы отправляете все в один кусок, вы платите Pc + 1 * Oc. Вы сохранили 9 * Oc. На самом деле сбережения, вероятно, больше, потому что (поскольку сжатие часто используется на обоих концах для уменьшения размера передаваемых данных), сжатие будет давать большие преимущества, если все данные будут сжаты вместе, чем если бы они сжаты как 10 кусков. (Примечание: в приведенном выше анализе отсутствуют данные, которые не подходят для покрытия.)

Кто-то может возразить: "Но вы сравниваете загрузку всех модулей отдельно и загружаете все модули в один кусок. Если мы загружаем по требованию, мы не будем загружать все модули". По сути, в большинстве приложений есть ядро ​​модулей, которые всегда будут загружаться, несмотря ни на что. Это модули, без которых приложение не будет работать вообще. Для некоторых небольших приложений это означает все модули, поэтому имеет смысл объединить все их вместе. Для больших приложений это означает, что основной набор модулей будет использоваться каждый раз, когда приложение запускается, но небольшой набор будет использоваться только по случаю. В последнем случае оптимизация должна создавать несколько пакетов. У меня есть приложение. Это редактор с режимами для различных задач редактирования. Хорошие 90% модулей относятся к ядру. Они будут загружены и использованы в любом случае, поэтому имеет смысл объединить их. Код для самих режимов не всегда будет использоваться, но все файлы для данного режима понадобятся, если режим загружен вообще, поэтому каждый режим должен быть его собственным пакетом. Таким образом, в этом случае модель с одним ядром и серией пучков режимов имеет смысл: а) оптимизировать развернутое приложение, но б) сохранить некоторые преимущества загрузки по требованию. Что красота RequireJS: она не требует, чтобы сделать то или другое исключительно.

Ответ 2

При разработке вы хотите иметь однофокусные мелкие файлы. Это приводит к их увеличению. При запуске в производство многие HTTP-запросы действительно вредят производительности. Затем снова вы не хотите загружать все приложение заранее - это тоже не оптимально.

Чтобы решить эту проблему, я создал небольшой проект в GitHub, require-lazy, вы можете назвать его плагином для строителя - r. JS. Он может ленить загружать части вашего приложения простым синтаксисом, а затем создавать отдельно загружаемые пакеты во время процесса сборки; поэтому, если ваше приложение состоит из 2 представлений, которые должны быть независимо загружены, require-lazy будет (идеально) создавать 3 js файла: (1) код начальной загрузки и общие библиотеки, (2) просмотр 1 со всеми его частными скриптами и (3 ) view 2 со всеми его частными скриптами.

Ленивая загрузка просто определяется как:

define(["lazy!view1"], function(view1) { .... });

И view1 должен быть доступен с обещанием:

view1.get().done(function(realView1) {
    ...
});

Проект доступен через npm, процесс сборки через grunt и компонент bower.

Комментарии более чем приветствуются.