Как реализовать lazy-loading компонентов или маршрутов?

В Vue ленивую загрузку (lazy-loading) компонентов и маршрутов реализуют для оптимизации производительности: тяжелые компоненты или страницы подгружаются только тогда, когда действительно нужны. Это особенно актуально при большом SPA-приложении, чтобы не грузить весь JavaScript сразу, а разбивать его на части (чанки), загружаемые по требованию. Такой подход основан на возможностях динамического import() и асинхронных компонентов.

Ленивая загрузка обычных компонентов

Vue поддерживает ленивую загрузку компонентов через функцию defineAsyncComponent. Этот подход позволяет загружать компонент только в момент, когда он требуется (например, при отображении по условию или скролле).

Пример:

import { defineAsyncComponent } from 'vue';
export default {
components: {
LazyComponent: defineAsyncComponent(() =>
import('./components/LazyComponent.vue')
)
}
};

В шаблоне:

<LazyComponent v-if="showComponent" />

Компонент LazyComponent.vue загрузится только тогда, когда showComponent === true.

Параметры defineAsyncComponent

Можно настроить поведение асинхронной загрузки:

const AsyncComp = defineAsyncComponent({
loader: () => import('./MyComponent.vue'),
loadingComponent: LoadingSpinner,
errorComponent: ErrorFallback,
delay: 200, // задержка перед показом loading-компонента
timeout: 3000 // ошибка, если не загрузился за 3 секунды
});

Ленивые маршруты с Vue Router

Vue Router позволяет использовать ленивую загрузку компонентов при конфигурации маршрутов. Это позволяет разбить приложение на чанки на уровне страниц.

Пример с import():

import { createRouter, createWebHistory } from 'vue-router';
const routes = \[
{
path: '/',
name: 'Home',
component: () => import('./views/HomeView.vue')
},
{
path: '/about',
name: 'About',
component: () => import('./views/AboutView.vue')
}
\];
const router = createRouter({
history: createWebHistory(),
routes
});

Здесь AboutView.vue попадёт в отдельный JavaScript-чанк и будет загружен только при переходе на /about.

Настройка имен чанков для Webpack

Если ты используешь Webpack, можно задать имя чанка через комментарий:

component: () => import(/\* webpackChunkName: "about" \*/ './views/AboutView.vue')

Это поможет при отладке и кешировании: вместо 1.js будет about.js.

Vite: автогенерация чанков

Vite сам разбивает чанки при использовании import() без нужды явно указывать webpackChunkName, так как он использует Rollup и умеет оптимизировать по умолчанию. Но для ручного контроля можно использовать /* @vite-ignore */ или кастомные плагины.

Ленивые модули с вложенными маршрутами

Ты можешь загружать не только компоненты, но и целые подмодули:

const routes = \[
{
path: '/admin',
component: () => import('./layouts/AdminLayout.vue'),
children: \[
{
path: 'dashboard',
component: () => import('./views/admin/Dashboard.vue')
},
{
path: 'settings',
component: () => import('./views/admin/Settings.vue')
}
\]
}
\];

Таким образом, всё под /admin будет загружено только при заходе в админку.

Ленивые компоненты с <Suspense> (Composition API)

С Vue 3 ты можешь использовать <Suspense> для отображения "заглушки" во время загрузки асинхронного компонента.

&lt;template&gt;
&lt;Suspense&gt;
&lt;template #default&gt;
&lt;LazyComponent /&gt;
&lt;/template&gt;
&lt;template #fallback&gt;
&lt;div&gt;Загрузка...&lt;/div&gt;
&lt;/template&gt;
&lt;/Suspense&gt;
&lt;/template&gt;
&lt;script setup&gt;
import { defineAsyncComponent } from 'vue';
const LazyComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
);
&lt;/script&gt;

<Suspense> работает только с асинхронными компонентами и оборачивает их в зону ожидания.

Примеры применения ленивой загрузки

  1. Маршруты — загрузка страниц только при переходе.

  2. Модальные окна — если модальное окно содержит тяжёлые таблицы/карты/редакторы, лучше подгружать их при открытии.

  3. Карточки товара с галереей — фото/слайдер можно грузить отдельно.

  4. Админ-панель — если она редко используется, можно грузить при входе.

  5. Редакторы кода/текста — такие компоненты большие и не нужны на старте.

  6. Чаты, уведомления, вкладки, lazy-tabs — грузятся только при активной вкладке.

Поддержка серверного рендеринга (SSR)

Асинхронные компоненты и маршруты требуют настройки серверного рендера для корректной предзагрузки на сервере. В SSR нужно уметь "предсказывать", какие чанки нужны. Для этого Vue 3 с @vue/server-renderer умеет отслеживать зависимости во время рендеринга и прикреплять preload-ссылки.

Кэширование лениво загружаемых компонентов

Можно кэшировать ленивые компоненты с помощью <KeepAlive>:

&lt;Suspense&gt;
&lt;KeepAlive&gt;
&lt;LazyComponent /&gt;
&lt;/KeepAlive&gt;
&lt;/Suspense&gt;

Это поможет избежать повторной загрузки и инициализации при возврате на компонент.

Отладка чанков и lazy-загрузки

  1. В браузере можно посмотреть вкладку "Network → JS", чтобы убедиться, что компоненты грузятся лениво.

  2. В сборке Vite/Webpack можно анализировать чанки с помощью плагинов:

    • rollup-plugin-visualizer

    • webpack-bundle-analyzer