Vue

Ленивая загрузка маршрутов

Магазин при первой загрузке тянет один большой JS-бандл, куда упакованы все экраны сразу: каталог, корзина, оформление, личный кабинет и редко используемая админка. Пользователь, который зашёл посмотреть один товар, всё равно качает код админки, которую никогда не откроет. Time to Interactive растёт, особенно на мобильном. Ленивая загрузка решает это: каждый маршрут грузится отдельным чанком только когда пользователь на него переходит, и стартовый бандл сжимается до того, что нужно для первого экрана.

  • Тяжёлая админка или раздел отчётов, которые открывает малая доля пользователей, не нужны в стартовом бандле
  • Магазин: первый экран это каталог, а код оформления заказа можно подгрузить при переходе в корзину
  • Страницы с тяжёлыми зависимостями (редактор, карта, графики) грузятся только при заходе на них
  • Мобильные пользователи на медленной сети получают быстрый первый рендер за счёт меньшего стартового бандла
  • Большие SPA с десятками экранов, где монолитный бандл вырастает до мегабайт

Предварительные знания

  • Конфигурация маршрутов и поле component из вводного урока
  • Идея бандлинга: сборщик упаковывает код в файлы для браузера
  • Базовое понимание динамического import как асинхронной загрузки модуля

Статический импорт против ленивого

При обычном статическом импорте компонент маршрута попадает в граф зависимостей точки входа, и сборщик кладёт его в стартовый бандл. Браузер скачивает и парсит весь этот код до того, как покажет первый экран, даже если пользователь никогда не дойдёт до большинства страниц. Чем больше экранов, тем тяжелее стартовый бандл.

Ленивая загрузка разрывает эту связь. Вместо готового компонента в поле component передаётся функция, возвращающая динамический import. Сборщик видит динамический import как точку разделения и выносит компонент в отдельный чанк, который загрузится только при первой навигации на маршрут.

Маршруты - естественный рубеж для разделения кода, потому что пользователь обычно видит один экран за раз. Граница между страницами совпадает с границей, по которой логично резать бандл на части.

Почему статический импорт всех компонентов маршрутов увеличивает время первой загрузки?

Динамический import для маршрута

Ленивый маршрут объявляется так: в поле component передаётся стрелочная функция, возвращающая динамический import нужного файла. Vue Router вызовет эту функцию при первой навигации на маршрут, дождётся загрузки чанка и отрендерит компонент. Сборщик автоматически создаёт отдельный файл для каждого такого import.

Разница в синтаксисе минимальна: было component: Catalog, стало component: () => import('./views/Catalog.vue'). Но эффект для сборки большой - каждый такой маршрут становится границей чанка. Можно смешивать: часто посещаемые экраны оставить статическими, а тяжёлые и редкие сделать ленивыми.

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

Как сделать маршрут ленивым в конфигурации Vue Router?

Когда ленивая загрузка помогает

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

СитуацияЛениво?Почему
Тяжёлая админка, доступная немногимДаБольшая часть пользователей никогда её не откроет
Редактор с тяжёлыми зависимостямиДаЗависимости не нужны на первом экране
Первый экран приложенияНетЕго всё равно показывают сразу, ленивость добавит лишний запрос
Крошечное SPA из двух экрановСкорее нетБандл и так мал, выгода от дробления незаметна

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

Делать ленивым первый экран контрпродуктивно: он показывается сразу при старте, поэтому его код всё равно нужен немедленно, а вынос в отдельный чанк лишь добавит круг до сервера перед первым рендером.

Какой маршрут разумнее всего сделать ленивым?

Связь с другими темами

Урок оптимизирует загрузку маршрутов из предыдущих уроков:

  • Основы роутера — Ленивая загрузка меняет поле component на функцию динамического import
  • Гварды — Проверка доступа гвардом до загрузки чанка экономит трафик на закрытых разделах
  • Pinia — Идея подгрузки по требованию применима и к коду, и к состоянию

Итог

  • Статический импорт компонента маршрута кладёт его в стартовый бандл, который грузится весь сразу при первом заходе
  • Динамический import в поле component делает маршрут ленивым: сборщик выносит компонент в отдельный чанк
  • Чанк маршрута загружается только при первой навигации на него, что уменьшает стартовый бандл и Time to Interactive
  • Это разделение кода на уровне маршрутов - самый естественный рубеж для разбиения SPA на части
  • Ленивая загрузка помогает на крупных приложениях и тяжёлых редких страницах, но для маленького SPA или первого экрана может только добавить лишних запросов

Связанные уроки

  • vue-24-router-intro — Ленивая загрузка меняет способ подключения компонента в конфигурации маршрута из вводного урока
  • vue-25-route-params-guards — Ленивые маршруты сочетаются с гвардами: проверка доступа до загрузки тяжёлого чанка экономит трафик
  • vue-27-pinia-intro — И код, и состояние выгодно подгружать по мере необходимости, а не всё сразу при старте
Ленивая загрузка маршрутов

0

1

Войти