В современных веб-приложениях большое значение имеет оптимизация начальной загрузки страницы. Чем больше JavaScript-кода загружается при старте приложения, тем дольше пользователь ожидает появления интерфейса. Одним из наиболее эффективных способов уменьшения объёма первоначально загружаемого кода является ленивая загрузка компонентов (Lazy Loading).
Ленивая загрузка — это техника, при которой компоненты и связанные с ними модули загружаются только в момент фактической необходимости, а не вместе со всем приложением.
В экосистеме Element Plus, которая предназначена для работы с Vue.js, данная техника используется особенно часто, поскольку библиотека содержит большое количество UI-компонентов: таблицы, формы, диалоги, всплывающие окна, уведомления, выпадающие списки и другие элементы интерфейса.
Применение ленивой загрузки позволяет:
Основой ленивой загрузки является разделение кода (Code Splitting). При сборке проекта такие инструменты как Vite или Webpack могут автоматически разбивать приложение на несколько независимых JavaScript-файлов.
В результате формируется:
Каждый чанк загружается динамически при необходимости.
Схема работы:
В Vue.js ленивую загрузку удобно реализовывать через динамический импорт.
const LazyComponent = () => import('./components/LazyComponent.vue')
В этом случае компонент:
Более гибким способом ленивой загрузки является использование функции
defineAsyncComponent.
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
Такой компонент ведёт себя как обычный, но его код загружается асинхронно.
Преимущества подхода:
Асинхронные компоненты могут показывать индикаторы загрузки.
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent({
loader: () => import('./components/Chart.vue'),
loadingComponent: LoadingComponent,
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})
Параметры:
| Параметр | Назначение |
|---|---|
| loader | функция загрузки |
| loadingComponent | компонент во время загрузки |
| errorComponent | отображается при ошибке |
| delay | задержка перед показом загрузки |
| timeout | максимальное время ожидания |
Библиотека Element Plus содержит десятки UI-компонентов. Если подключить библиотеку целиком, размер бандла может значительно увеличиться.
Поэтому используется импорт только нужных компонентов.
import { ElTable, ElButton } from 'element-plus'
Однако даже такой импорт может быть включён в основной бандл.
Для тяжёлых компонентов можно использовать асинхронный импорт.
import { defineAsyncComponent } from 'vue'
const ElTable = defineAsyncComponent(() =>
import('element-plus/es/components/table')
)
Теперь таблица загрузится только в момент использования.
Модальные окна часто используются редко, поэтому их удобно загружать асинхронно.
const UserDialog = defineAsyncComponent(() =>
import('@/components/dialogs/UserDialog.vue')
)
Пример использования:
<UserDialog v-if="dialogVisible" />
Компонент будет загружен только при открытии диалога.
Наиболее распространённая практика — ленивое подключение страниц приложения.
В маршрутизаторе Vue Router это реализуется через динамический импорт.
const routes = [
{
path: '/dashboard',
component: () => import('../views/Dashboard.vue')
},
{
path: '/users',
component: () => import('../views/Users.vue')
}
]
Каждая страница становится отдельным чанком.
Когда страница загружается асинхронно, все используемые внутри неё компоненты Element Plus также могут быть вынесены в отдельный чанк.
Пример страницы:
<script setup>
import { ElTable, ElButton } from 'element-plus'
</script>
<template>
<el-table :data="tableData">
<el-table-column prop="name" label="Name"/>
<el-table-column prop="email" label="Email"/>
</el-table>
<el-button type="primary">
Добавить пользователя
</el-button>
</template>
Если страница загружается лениво, то и код этих компонентов не попадает в основной бандл.
Для упрощения работы часто используется плагин unplugin-vue-components.
Он автоматически:
Пример конфигурации:
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default {
plugins: [
Components({
resolvers: [ElementPlusResolver()]
})
]
}
После этого можно использовать компоненты без явного импорта.
<el-button type="primary">Кнопка</el-button>
Плагин автоматически подключит ElButton.
В больших интерфейсах часто используются сложные компоненты:
Такие компоненты целесообразно выносить в отдельные лениво загружаемые модули.
Пример:
const AnalyticsPanel = defineAsyncComponent(() =>
import('@/modules/analytics/AnalyticsPanel.vue')
)
Это позволяет:
Иногда требуется ускорить отображение лениво загружаемых компонентов. Для этого используется prefetch или preload.
Сборщики могут добавлять специальные комментарии.
Пример для Webpack:
const SettingsPage = () =>
import(/* webpackPrefetch: true */ './SettingsPage.vue')
Это сообщает браузеру загрузить компонент заранее, когда система простаивает.
Асинхронная загрузка может завершиться ошибкой:
Поэтому рекомендуется добавлять обработку ошибок.
const AsyncComponent = defineAsyncComponent({
loader: () => import('./Chart.vue'),
errorComponent: ErrorBlock,
retryDelay: 2000,
maxRetries: 3
})
Такой подход повышает устойчивость интерфейса.
В Vue.js существует компонент Suspense,
предназначенный для работы с асинхронными компонентами.
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
Пока компонент загружается, отображается резервный интерфейс.
Наиболее подходящие кандидаты для ленивой загрузки:
Некоторые элементы должны загружаться сразу:
Если компонент используется практически на каждой странице, его асинхронная загрузка может привести к лишним сетевым запросам.
При работе с Element Plus в крупных проектах часто используется следующая архитектура:
Основной бандл
Асинхронные чанки
Такой подход позволяет поддерживать баланс между: