Здесь, в 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