16. Оптимизация сборки
Оптимизация production сборки — ключевой шаг для создания быстрых приложений. Vite предоставляет мощные инструменты для code splitting, анализа бандла и уменьшения размера итоговых файлов.
Code Splitting стратегии
Заголовок раздела «Code Splitting стратегии»Dynamic Import — самый важный приём
Заголовок раздела «Dynamic Import — самый важный приём»// ❌ Плохо: всё в одном бандлеimport Dashboard from './pages/Dashboard'import Settings from './pages/Settings'import AdminPanel from './pages/AdminPanel'
// ✓ Хорошо: каждая страница загружается по требованиюconst Dashboard = lazy(() => import('./pages/Dashboard'))const Settings = lazy(() => import('./pages/Settings'))const AdminPanel = lazy(() => import('./pages/AdminPanel'))
// Vite автоматически создаст:// assets/Dashboard-abc.js (загрузится при /dashboard)// assets/Settings-def.js (загрузится при /settings)// assets/AdminPanel-ghi.js (загрузится при /admin)manualChunks — Ручное управление чанками
Заголовок раздела «manualChunks — Ручное управление чанками»build: { rollupOptions: { output: { manualChunks: { // Реакт в отдельный чанк (большой, редко меняется → хорошо кэшируется) 'vendor-react': ['react', 'react-dom', 'react-router-dom'],
// UI библиотека отдельно 'vendor-ui': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
// Data fetching 'vendor-query': ['@tanstack/react-query', 'axios'],
// Утилиты 'vendor-utils': ['lodash-es', 'date-fns', 'zod'], }, }, },}Tree Shaking
Заголовок раздела «Tree Shaking»// ✓ Named imports — tree-shakeable!import { format, parseISO } from 'date-fns'// В бандл попадёт ТОЛЬКО format и parseISO
// ❌ Default import всей библиотеки — НЕ tree-shakeableimport _ from 'lodash'// Весь lodash (70KB) попадёт в бандл!
// ✓ lodash-es — ESM версия, полностью tree-shakeableimport { debounce, throttle } from 'lodash-es'// Только debounce и throttlerollup-plugin-visualizer — Анализ бандла
Заголовок раздела «rollup-plugin-visualizer — Анализ бандла»npm i -D rollup-plugin-visualizerimport { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({ plugins: [ react(), visualizer({ open: true, // Открыть в браузере после сборки gzipSize: true, // Показать размер после gzip brotliSize: true, // Показать размер после brotli filename: 'stats.html', template: 'treemap', // 'treemap' | 'sunburst' | 'network' }), ],})Минификация и сжатие
Заголовок раздела «Минификация и сжатие»// esbuild (по умолчанию) — быстроbuild: { minify: 'esbuild',}
// terser — лучшее сжатиеbuild: { minify: 'terser', terserOptions: { compress: { drop_console: true, // Удалить console.log drop_debugger: true, // Удалить debugger pure_funcs: ['console.log'], // Аналог drop_console }, mangle: { safari10: true, // Фикс для Safari 10 }, },}Preload / Prefetch директивы
Заголовок раздела «Preload / Prefetch директивы»// Vite автоматически добавляет <link rel="modulepreload">// для критических чанков
// Настройка в vite.config.ts:build: { modulePreload: { polyfill: true, // Полифил для браузеров без modulepreload },}Оптимизация изображений
Заголовок раздела «Оптимизация изображений»# Плагин для сжатия изображенийnpm i -D vite-plugin-imageminimport viteImagemin from 'vite-plugin-imagemin'
plugins: [ react(), viteImagemin({ gifsicle: { optimizationLevel: 7 }, mozjpeg: { quality: 80 }, pngquant: { quality: [0.8, 0.9] }, svgo: { plugins: [{ name: 'removeViewBox' }] }, }),]Анализ bundle size в CI
Заголовок раздела «Анализ bundle size в CI»build: { // Предупреждение если чанк > 500KB chunkSizeWarningLimit: 500,
// Подробный вывод о размерах reportCompressedSize: true,}Ниже — интерактивный анализатор бандла: включай/выключай зависимости и смотри как меняется размер: