С момента появления JS на стороне клиента, берущего под свой контроль Интернет, мы наблюдали огромное количество JS, написанных или включенных в наши веб-приложения. Прошли те времена, когда наши серверы использовали для рендеринга html для наших веб-приложений (хотя они использовались для начального рендеринга на стороне сервера). Сегодня нам нужно больше от наших веб-приложений, таких как отложенная загрузка данных через Ajax, классная анимация, управление состоянием приложения, маршрутизация, бесконечная прокрутка и многое другое.

Все это требует от фронтенд-разработчика приличной работы над JavaScript. Результатом является огромный пул файлов JS, поскольку разработка для внешнего интерфейса требует зависимости от какой-либо библиотеки или фреймворка или, по крайней мере, jQuery. Написание всего кода на VanillaJS - занятие не для всех. Помимо этого, вы также стремитесь сохранить свой код модульным, используя шаблоны проектирования, а именно модульный шаблон, заводской шаблон, одноэлементный шаблон, шаблон наблюдателя и т. Д. Эти вещи занимают важное место в разработке. Я не могу представить себе разработку сложного веб-приложения без использования таких шаблонов проектирования.

Теперь при сохранении модульного кода это полезно для целей разработки, но не идеально для вашей производственной среды. Это очень важный шаг в веб-оптимизации - объединить все файлы в один перед развертыванием в производственной среде. Почему? поскольку создание отдельного сетевого запроса http для всех этих модульных файлов неэффективно. Выполнение 1 запроса для связанного файла с более чем 100 запросами на выборку 100 файлов более эффективно. Итак, как видите, между двумя подходами существует своего рода компромисс. Последний подход может предоставить вам такие вещи, как отложенная загрузка модулей по запросу, но приводит к большому количеству сетевых запросов. Первый подход эффективно выполняет единичный запрос и сокращает частые обращения к серверу, но в то же время значительно снижает время начальной загрузки. CRP (критический путь рендеринга) вашего веб-приложения не должен включать длительную блокировку Javascript, так как он может блокировать время начальной загрузки, создавая плохие впечатления для ваших первых пользователей и, что еще хуже, в медленной сети.

Итак, ясно одно: нам просто нужно связать файлы JS для производства, сохраняя при этом низкое время начальной загрузки. Тогда как мы можем выйти из этого тупика? Ответ - разделение кода или фрагменты, то есть мы можем найти золотую середину между этими двумя вещами, увеличив количество запросов, сохранив их вместе.

Мое обсуждение будет следовать моему любимому инструменту связывания webpack. Но эта концепция разбиения на части присутствует во всех других сборщиках, таких как browserify, requirejs или almondjs. Возвращаясь к обсуждению, для большинства наших веб-приложений у нас есть два типа кодов: один написан нами, а другой, от которого мы зависим, или сторонние библиотеки, можно сказать. Теперь разумно сначала разделить их. Причину я вам скоро скажу.

Выше представлены две иллюстрации с размерами моих файлов в комплекте до и после разделения. Как вы можете видеть, мой index.js имеет размер 666 КБ (после минификации) на первом снимке экрана, и когда я переместил весь код поставщика или стороннего производителя в vendor.js, он стал 1,1 МБ + 172 КБ. Это раздувание связано с тем, что я включил в свой проект реакции всю библиотеку Material UI, а не отдельные компоненты, как в первом случае. Но давайте не будем отказываться от обсуждения этого вопроса. Придерживаясь сути, мы успешно завершили первую фазу разбиения на части.

Давай сделаем еще немного. Допустим, я хочу кэшировать этот vendor.js на клиентском компьютере пользователя на более длительный период времени, используя, возможно, сервис-воркер, кеширование на стороне сервера или отправляя его вместе со сборкой приложения для Android, как я делаю на моей текущей работе. Дело в том, что наш vendor.js не будет так часто меняться по сравнению с моим собственным написанным кодом в форме index.js. Двигаясь дальше, мы должны выполнить управление версиями, чтобы убедиться, что наш файл vendor.js не меняется с течением времени. Также для создания содержимого на основе хэшей для нашего vendor.js нам нужно будет отделить от него код времени выполнения веб-пакета, скажем, на meta.js или init.js. См. Этот выпуск на github. Результат будет примерно таким.

Кроме того, чтобы сделать ваш vendor. [Chunkhash] .js полностью статическим, используйте этот новый веб-пакет NamedModulesPlugin, поскольку он использует имена файлов модулей вместо динамически сгенерированных файлов во время сборки. Это все небольшие предостережения, которые я придумал при работе с webpack.

Круто, до сих пор мы отделили среду выполнения от наших vendorjs, автоматическое управление версиями на основе контента было выполнено. Наши файлы сборки готовы к кэшированию. Осталась только одна крошечная вещь, фактически главная проблема, как мы будем включать эти динамически сгенерированные хешированные имена файлов в мой index.html ?? Не волнуйтесь, существует веб-пакет HtmlWebpackPlugin, который точно решит эту проблему. Вы можете использовать это так

Как видите, я использую шаблон ejs для создания файла index.html. Вы можете пропустить это и установить для параметра inject значение true, которое будет автоматически вводить сгенерированные файлы js в конце перед закрывающим тегом body. Мое требование было другим, так как мне пришлось встроить свои файлы с версией в шаблон Django, который уже зарезервирован {{}}, иначе я мог бы использовать усы или ручки. Вы можете проверить дополнительные параметры в документации HtmlWebpackPlugin.

Вуаля! Мы только что завершили преобразование нашего веб-приложения, готового для кэширования стороннего поставщика. [Chunkhash] .js. Теперь все, что изменится со временем, - это index. [Hash] .js. Таким образом, 90% времени загрузки уже было сокращено для последующих загрузок страниц на пользовательском компьютере, поскольку хэш файла поставщика останется неизменным на протяжении всего процесса. Теперь все, что нам нужно сосредоточить, - это index. [Hash] .js, который в нашем случае составляет 172 КБ. В дальнейшем мы можем разбить это на части и загружать их по требованию при таких событиях, как наиболее частое изменение маршрута.

Давайте попробуем с реактивным маршрутизатором. React Router позволяет добавлять хуки к маршрутам перед навигацией. Итак, что вы можете сделать, это указать загрузку определенного модуля с помощью require.ensure или System.import с webpack 2. Давайте придерживаться первого.

Выше - реализация ленивой загрузки маршрута. Кстати, я попытался абстрагироваться от функции обработчика getComponent, но по каким-то странным причинам, требующим контекста, она не принимала динамические параметры из замыкания (если вы можете решить эту проблему, пожалуйста, дайте мне знать). В любом случае, давайте посмотрим, запустим веб-пакет и проанализируем вывод.

Размер индекса. [Hash] .js уменьшился со 173 кБ до 113 кБ. Его размер примерно на 35% меньше, так что вы можете ожидать более быстрой начальной загрузки, чем раньше. И когда вы переходите к определенному маршруту, соответствующий фрагмент будет загружаться лениво по запросу.

Уф! Это было утомительно. Это было? Вам решать. Но в конце концов пользователи вашего приложения будут довольны, что делает наши усилия достойными. Итак, трансформируйте свое веб-приложение, воспользовавшись этими удивительными преимуществами, которые предлагает веб-пакет, чтобы вы могли улыбнуться пользователям вашего приложения.

Резюме

Итак, мы узнали о том, почему объединение важно, как разделить код вашего поставщика и собственный код приложения для реализации кеширования, управления версиями ваших файлов для правильной очистки кеша. Я уверен, что вы могли застрять в ситуации вроде Я развернул свой последний код на сервере, но все еще использую старую версию в своем приложении. Мы узнали, что автоматическое управление версиями Webpack может помочь вам облегчить такие проблемы (например, index.js? V = 2). После этого наш отдельный индексный файл размером 173 КБ был уменьшен до 113 КБ с помощью отложенной загрузки с помощью response-router.

Надеюсь, вам понравился мой пост. Мне очень понравилось писать это, и, фактически, я многому научился во время написания. Если вы тоже, пожалуйста, порекомендуйте и прокомментируйте.

Благодарю вас!