Code splitting
Last updated
Was this helpful?
Last updated
Was this helpful?
Когда приложение становится достаточно большим, монолитный бандл со всем исходным кодом загружается, парсится и исполняется, долго (секунды, особенно на мобильных). Но если пользователь заходит на страницу логина, не имеет смысла загружать остальную часть приложения.
Секция приложения может импортировать большое количество компонентов, которые не нужны при первой загрузке. Необходимо разбивать бандл на отдельные файлы (chunks, чанки) и загружать их динамически, только когда это необходимо.
Create React App поддерживает разделение кода и позволяет динамически импортировать части приложения используя import()
.
Первый подход состоит в разбиении приложения на отдельные маршруты и загрузке каждого маршрута асинхронно. Этого вполне достаточно для большинства приложений, переходим на новый раут - загружается необходимый код для его обслуживания.
Но есть еще один вариант. Раут это просто компонент. Поэтому можно разделять код на уровне компонентов, а не маршрутов. Какая в этом выгода?
В действительно большом приложении - огромная. Интерфейсы могут быть очень громоздкими, и в тех местах, где модальные окна, вкладки, скрытые формы и т. п., не нужны до определенного действия пользователя, разделение кода помогает ускорить рендер страницы.
Это не значит что необходимо использовать один или другой подход, используйте оба. Делите и маршруты, и части страницы, это все просто компоненты. Как, что и где разделять это целиком ваше решение, зависящее от сложившейся ситуации.
Чрезмерный сплитинг, кстати, тоже не лучшая идея. HTTP-запрос за файлом может быть дольше чем добавленный вес к первой загрузке.
Функция asyncComponent
принимает объект настроек из двух свойств: loader
- функция, которая при вызове будет динамически импортировать компонент, loading
- компонент который будем показывать пока идет HTTP-запрос.
В componentDidMount
мы просто вызываем функцию loader
, и сохраняем динамически загруженный компонент в состояние.
После чего делаем рендер по условию, где рендерим загруженный компонент, если он уже загрузился. В противном случае рендерим компонент Loading
.
Теперь используем эту функцию для динамической загрузки страниц.
Важно понимать, что здесь не происходит импорта компонента. Мы передаем функцию которая будет использована для динамического импорта, когда будет создан компонент AsyncHome
.
Может показаться странным, что мы передаем функцию. Почему бы просто не передать строку './pages/Home'
, а затем выполнить динамический импорт внутри asyncComponent
?
Это связано с тем, что мы хотим явно указать компонент, который мы динамически импортируем. Основываясь на этом, Webpack разбивает наше приложение. Он смотрит на эти импорты и генерирует необходимые чанки (куски, chunks).
После создания AsyncHome
мы можем использовать его в маршрутах. При совпадении маршрута, React Router создаст экземпляр компонента AsyncHome
, который, в свою очередь, динамически импортирует компонент Home
и отрендерит его.
Каждый из файлов .chunk.js
- это вызовы import()
, асинхронно загружаемые компоненты.
Если необходимо дать чанкам вменяемые имена, делается это так:
Что произойдет, если запрос на импорт нового компонента займет слишком много времени или HTTP-запрос не удастся. Или, возможно, необходимо предварительно загрузить определенные компоненты. Например, пользователь находится странице логина, и необходимо предварительно загрузить домашнюю страницу.
React Loadable
- небольшая библиотека, которая упрощает разделение компонентно-ориентированного кода.
Loadable
- компонент высшего порядка, который позволяет легко разделить код на уровне компонентов.
Добавим пакет в проект.
Достаточно заменить asyncComponent
на Loadable
и все продолжит работать как и раньше.
Одно но, можно улучшить компонент Loading
, потому что react-loadable
прокидывает ему несколько очень полезных свойств.
Официальный API который позволяет рендерить динамически загружаемый компонент. Заменит react-loadable
.
Принимает функцию-згарузчик которая возвращает результат динамического импорта - промис, значение которого будет дефолтный экспорт модуля, реакт компонент.
Если во время ренедера MyComponent
, компонент AsyncComponent
еще не загружен, необходимо показать фолбек. Для этого используется компонент Suspense
. Проп fallback
принимает любой React-элемент. Susupense
можно поместить в любом месте над асинхронным компонентом, даже оборачивая целую группу.