Здесь, в Innovid, ведущей платформе видеомаркетинга, где мы обслуживаем 1,3 миллиона часов видео в день, мы любим Webpack и используем его во многих наших веб-проектах.
Недавно мы перенесли один из наших проектов на платформу новый Webpack 4 , который предоставляет сразу несколько замечательных функций, включая резкое сокращение времени сборки.
Как часть В процессе миграции мы решили также разделить код на основную часть нашего приложения, используя одну из самых привлекательных функций, которые может предложить Webpack:
Ленивая загрузка.

Разделение кода вашего приложения может помочь вам отложить загрузку только тех вещей, которые в данный момент необходимы пользователю, что может значительно улучшить производительность вашего приложения. Хотя вы не уменьшили общий объем кода в своем приложении, вы избежали загрузки кода, который может никогда не понадобиться пользователю, и уменьшили количество кода, необходимого во время начальной загрузки. - Реагирующая документация

Webpack строит граф зависимостей из вашего приложения. Начиная с ваших точек входа, он просматривает ваши файлы и их зависимости, выполняет всевозможные магические действия, такие как запуск ваших файлов с помощью нескольких загрузчиков и плагинов, и, наконец, выводит ваши сгенерированные пакеты, которые затем передаются клиентам.

В настоящее время мы разделяем наши сгенерированные пакеты на два файла: app.js (код нашего приложения) и vendors.js (наши сторонние библиотеки) .
Мы использовали webpack-bundle-analyzer, чтобы получить красивый вид двух наших сгенерированных пакетов:

Конфигурации Webpack

app объединяется автоматически, поскольку это точка входа в наше приложение.
Сторонние vendors объединяются с использованием новой конфигурации optimization и путем указания, что пакет vendors должен включать все файлы, которые импортируются из наших node_modules :

Примечание. В Webpack 4 мы больше не используем CommonChunkPlugin.. Он был удален в пользу нового API с именами splitChunks и runtimeChunk.

Отложенная загрузка компонентов React

В настоящее время пакеты vendors и app - это те пакеты, которые наши клиенты сначала загружают при первой загрузке страницы. Мы поняли, что можем улучшить это, отложив загрузку довольно «тяжелого» компонента и уменьшив размеры первоначально обслуживаемых пакетов.

Например: redux-form (библиотека для управления формами в приложениях React redux), которая используется только в большом компоненте с именем GenerateTags, является хорошим кандидатом для отложенной загрузки, поскольку он довольно большой и используется только в определенных сценариях. Зависимость redux-form и наш GenerateTags компонент могут быть извлечены в другой блок, что приведет к меньшему размеру пакета, обслуживаемому при рендеринге первой страницы.

Мы изучили популярную библиотеку под названием react-loadable для использования динамического импорта, которая, по сути, является оболочкой для будущего javascript import() syntax (это часть этапа 3 процесс TC39).

После этого изменения наши бандлы выглядели так:

Результат почти такой, как мы хотели, но redux-form по-прежнему включен в пакет vendors, и мы хотели, чтобы redux-form и GenerateTags обслуживались разными частями и были ленивы загружается по запросу.

Это произошло потому, что redux-form также импортируется в другой файл, где мы добавляем редуктор redux в наш combineReducers redux работают так:

Оператор static import вверху заставляет библиотеку redux-form быть частью нашего vendors пакета. В этом есть смысл: Webpack понял, что его нельзя загружать лениво, поскольку он статически импортируется как часть дерева зависимостей точки входа в наше приложение.
Чтобы улучшить это, мы решили динамически внедрить редуктор redux-form . Сначала мы удалили импорт редуктора redux-form вверху и добавили код, позволяющий динамически вводить редукторы redux:

Наконец, мы вызываем наш injectAsyncReducer из компонент componentDidMount of GenerateTags:

Обратите внимание, что получение прямой ссылки на хранилище из компонента не рекомендуется и может быть довольно проблематичным при рендеринге на стороне сервера.
Вы можете узнать больше о внедрении асинхронных редукторов, а также о более чистом способе внедрения редуктор, использующий HOC (компонент высокого порядка) здесь.

Конфигурации машинописного текста

Поскольку мы используем Typescript в нашем проекте, нам пришлось обновить свойство module до esnext и установить для свойства removeComments значение false в нашем tsconfig.json file (версия Typescript должна быть ≥ 2.4 для поддержки динамического импорта). Это позволит вести динамический импорт. сообщая компилятору машинописного текста оставить наши операторы импорта в покое и не переносить их вместе со своими встроенными комментариями, позволяя Webpack взять на себя управление и творить волшебство.

Окончательный результат выглядит так:

Наконец, мы достигли того, что хотели, GenerateTags вместе с его зависимостью redux-form теперь отделены от нашего vendors пакета и лениво загружаются по запросу.

Резюме

Мы рекомендуем прочитать больше о методах оптимизации с помощью Webpack по этой ссылке.

  • Используя динамический импорт в вашем приложении, вы можете уменьшить окончательные размеры пакетов, обслуживаемых при загрузке первой страницы, и обеспечить более быстрое время загрузки, отложив загрузку определенных частей вашего приложения.
  • Typescript поддерживает динамический импорт начиная с версии 2.4. Вам нужно только запомнить установку нескольких свойств в tsconfig.json для поддержки этой функции.
  • Переход на Webpack 4 довольно прост. В настоящее время существует не так много документации по новым конфигурациям и API, но она определенно скоро улучшится.
  • Динамическое введение редукторов redux - хороший трюк, чтобы держать руку на пульсе. Это позволило нам отложить загрузку библиотеки, которая использовала редуктор redux в нашем приложении.

Ссылки:
*
RIP CommonsChunkPlugin
* https://reactjs.org/docs/code-splitting.html
* https: // medium.com/front-end-hacking/lazy-loading-with-react-and-webpack-2-8e9e586cf442
* https://blogs.msdn.microsoft.com/typescript/2017/06/ 27 / announcing-typescript-2-4 /
* https://survivejs.com/webpack/building/code-splitting/
* https://medium.com/front- end-hacking / lazy-loading-with-react-and-webpack-2-8e9e586cf442
* https://tylergaw.com/articles/dynamic-redux-reducers/
* https : //stackoverflow.com/questions/32968016/how-to-dynamically-load-reducers-for-code-splitting-in-a-redux-application
* https://developers.google.com / web / updates / 2017/11 / dynamic-import
* https://reacttraining.com/react-router/web/guides/code-splitting