Отчёт о размере бандла

При сборке проекта через Vite формируется набор итоговых файлов: JavaScript-бандлы, CSS-файлы, изображения, шрифты, динамические чанки и вспомогательные ресурсы. Размер этих файлов напрямую влияет на:

  • скорость загрузки приложения;
  • время инициализации JavaScript;
  • показатель Time to Interactive;
  • производительность мобильных устройств;
  • потребление трафика;
  • эффективность кеширования.

Контроль размера бандла становится особенно важным в крупных SPA-приложениях, библиотеках, SSR-проектах и микрофронтендах.

Vite предоставляет встроенную информацию о размере выходных файлов после выполнения production-сборки.


Базовый отчёт после сборки

Команда production-сборки:

npm run build

После завершения Vite выводит таблицу с информацией о файлах:

dist/assets/index-8d91f.js      185.32 kB │ gzip: 61.22 kB
dist/assets/vendor-a2c11.js     540.10 kB │ gzip: 180.40 kB
dist/assets/index-91ab2.css      24.11 kB │ gzip: 5.30 kB

Здесь отображаются:

  • оригинальный размер файла;
  • размер после gzip-сжатия;
  • имя итогового чанка;
  • расширение ресурса.

Что означают размеры

Original Size

Физический размер файла без сжатия:

540.10 kB

Именно этот файл хранится на сервере.


Gzip Size

Размер после gzip-компрессии:

gzip: 180.40 kB

Большинство веб-серверов отдают именно gzip-версию ресурса.

Реальный сетевой трафик обычно ближе именно к gzip-размеру.


Почему размер бандла критически важен

Медленный парсинг JavaScript

Даже если файл хорошо сжат, браузеру всё равно необходимо:

  1. скачать код;
  2. распаковать;
  3. распарсить;
  4. скомпилировать;
  5. выполнить.

Большой bundle способен блокировать главный поток браузера.


Ухудшение First Load

Если весь проект собирается в один огромный chunk:

app.js → 3 MB

браузер вынужден загружать весь код сразу, даже если пользователь открыл одну страницу.


Проблемы мобильных устройств

Слабые CPU значительно медленнее выполняют parsing и compilation JavaScript.

На desktop 1 MB JS может обрабатываться быстро, а на бюджетном смартфоне — вызывать серьёзные задержки.


Предупреждение Vite о большом чанке

Vite автоматически показывает warning:

(!) Some chunks are larger than 500 kBs after minification.

По умолчанию лимит:

500 kB

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


Настройка лимита warning

Параметр:

build.chunkSizeWarningLimit

Пример:

import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    chunkSizeWarningLimit: 1000
  }
})

Теперь warning появится только после превышения 1000 kB.


Почему не стоит просто увеличивать лимит

Неправильный подход:

chunkSizeWarningLimit: 5000

Это скрывает проблему, а не решает её.

Большой bundle обычно сигнализирует о:

  • неправильном code splitting;
  • лишних зависимостях;
  • дублировании библиотек;
  • отсутствии lazy loading;
  • попадании dev-кода в production.

Анализ структуры бандла

Стандартного вывода Vite недостаточно для глубокого анализа.

Для этого используются специальные visualizer-инструменты.

Наиболее популярный вариант:

npm install --save-dev rollup-plugin-visualizer

Подключение visualizer

Конфигурация:

import { defineConfig } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ]
})

Что показывает visualizer

После сборки создаётся HTML-отчёт.

В нём отображаются:

  • все чанки;
  • зависимости;
  • вложенные модули;
  • размер каждого пакета;
  • вклад библиотек в итоговый bundle;
  • tree shaking;
  • динамические импорты.

Типы визуализации

Treemap

Самый популярный режим.

Каждый прямоугольник — отдельный модуль.

Чем больше прямоугольник — тем тяжелее модуль.


Sunburst

Кольцевая структура зависимостей.

Полезна для анализа вложенности пакетов.


Network Graph

Отображение зависимостей в виде графа.

Удобно для поиска циклических импортов.


Анализ vendor-бандла

Часто самый большой файл:

vendor.js

Внутри обычно находятся:

  • React;
  • Vue;
  • lodash;
  • chart libraries;
  • editor libraries;
  • UI frameworks.

Поиск тяжёлых зависимостей

Visualize-отчёт часто показывает неожиданные проблемы.

Пример:

moment.js → 300 kB

или:

lodash full build → 500 kB

Замена тяжёлых библиотек

Moment → Day.js

Вместо:

import moment from 'moment'

лучше:

import dayjs from 'dayjs'

Lodash Full Import

Плохой вариант:

import _ from 'lodash'

Лучше:

import debounce from 'lodash/debounce'

или:

import { debounce } from 'lodash-es'

Tree Shaking

Vite использует Rollup для production-сборки.

Rollup умеет удалять неиспользуемый код.

Пример:

import { debounce } from 'lodash-es'

В bundle попадёт только debounce.


Почему tree shaking может не работать

Причины:

  • CommonJS-пакеты;
  • side effects;
  • неправильные импорты;
  • динамические require;
  • legacy-библиотеки.

Side Effects

Некоторые библиотеки помечают:

{
  "sideEffects": false
}

Это позволяет Rollup безопасно удалять неиспользуемые модули.


Анализ CSS-размера

Большие CSS-файлы также ухудшают загрузку.

Причины:

  • огромные UI frameworks;
  • неиспользуемые стили;
  • дублирование;
  • глобальные utility-классы.

Tailwind и purge

Без purge CSS Tailwind может быть огромным.

Production-конфигурация:

content: [
  './index.html',
  './src/**/*.{js,ts,jsx,tsx}'
]

Неиспользуемые классы будут удалены.


Dynamic Import

Главный инструмент уменьшения initial bundle.

Пример:

const AdminPanel = () => import('./AdminPanel')

Код загрузится только при необходимости.


Code Splitting

Vite автоматически создаёт отдельные чанки для dynamic imports.

Результат:

main.js
admin.js
chart.js
editor.js

Lazy Loading страниц

Для роутеров:

const Home = lazy(() => import('./pages/Home'))
const Profile = lazy(() => import('./pages/Profile'))

Это резко уменьшает размер первого чанка.


Разделение vendor-кода

Через manualChunks:

build: {
  rollupOptions: {
    output: {
      manualChunks: {
        react: ['react', 'react-dom'],
        editor: ['monaco-editor'],
        charts: ['chart.js']
      }
    }
  }
}

Польза manualChunks

Позволяет:

  • лучше кешировать зависимости;
  • отделять тяжёлые библиотеки;
  • ускорять повторные загрузки;
  • уменьшать invalidation cache.

Brotli Size

Некоторые visualizer-плагины показывают:

brotli size

Brotli обычно эффективнее gzip.

Современные CDN часто используют именно Brotli-сжатие.


Анализ duplicated modules

Иногда bundle содержит дубли:

lodash x2
react x2

Причины:

  • разные версии пакетов;
  • nested dependencies;
  • неправильный dependency graph.

Проверка дубликатов

Команды:

npm ls react

или:

npm ls lodash

Dependency Optimization

Vite использует pre-bundling через esbuild.

Однако production bundle строится Rollup.

Иногда dev и production размеры заметно отличаются.


Sourcemap-анализ

Можно включить sourcemaps:

build: {
  sourcemap: true
}

Это помогает анализировать итоговый bundle.


Hidden Sourcemap

Для production monitoring:

build: {
  sourcemap: 'hidden'
}

Sourcemap создаётся, но не публикуется в браузер.


Использование bundle analyzer в CI

Размер бандла можно контролировать автоматически.

Например:

  • GitHub Actions;
  • GitLab CI;
  • Jenkins;
  • Azure Pipelines.

Bundle Budget

Можно задавать лимиты:

main.js < 200 kB
vendor.js < 500 kB

При превышении pipeline падает.


Проверка размеров через scripts

Пример:

{
  "scripts": {
    "analyze": "vite build"
  }
}

или:

{
  "scripts": {
    "build:report": "vite build --mode production"
  }
}

Отдельная сборка для анализа

Иногда visualizer подключают только в analysis mode:

plugins: [
  mode === 'analyze' && visualizer()
]

Использование mode

Пример:

vite build --mode analyze

Conditional Plugin Loading

Полноценный пример:

export default defineConfig(({ mode }) => ({
  plugins: [
    mode === 'analyze'
      ? visualizer({
          open: true
        })
      : null
  ]
}))

Анализ загрузки по маршрутам

Крупные SPA могут иметь разные entry points.

Важно понимать:

  • какой chunk загружается;
  • какие страницы тянут тяжёлые зависимости;
  • какие модули попадают в initial load.

Ошибка giant shared chunk

Иногда общий chunk становится слишком большим:

shared.js → 2 MB

Причина:

  • чрезмерное переиспользование;
  • неправильное split strategy;
  • огромный shared vendor.

Стратегии уменьшения shared chunk

Подходы:

  • ручное разделение manualChunks;
  • dynamic imports;
  • lazy loading;
  • выделение admin-зоны;
  • разделение editor/charts/maps.

Анализ библиотечного режима

В library mode размер особенно важен.

Поскольку bundle будет использоваться сторонними приложениями.


External Dependencies

В библиотеках часто исключают зависимости:

rollupOptions: {
  external: ['react']
}

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


Проверка tree shaking библиотеки

Важно убедиться, что библиотека:

  • использует ES modules;
  • не содержит side effects;
  • экспортирует независимые модули.

Source Map Explorer

Дополнительный инструмент:

npm install --save-dev source-map-explorer

Анализ через source-map-explorer

Пример:

npx source-map-explorer dist/assets/*.js

Инструмент показывает:

  • структуру bundle;
  • неиспользуемый код;
  • размер зависимостей.

Rollup Bundle Analyzer

Альтернатива visualizer:

npm install --save-dev rollup-plugin-analyzer

Console-отчёт

Некоторые анализаторы выводят статистику прямо в терминал:

Bundle size: 1.2 MB
Modules: 742
Treeshaked: 38%

Контроль регрессий

Без постоянного анализа bundle постепенно разрастается.

Типичные причины:

  • новые зависимости;
  • тяжёлые UI-kit;
  • chart libraries;
  • rich text editors;
  • случайные full imports.

Практика регулярного анализа

Оптимальная стратегия:

  • анализировать bundle после крупных изменений;
  • проверять vendor chunk;
  • следить за initial load;
  • отслеживать gzip и brotli размеры;
  • использовать CI budgets.

Типичные целевые размеры

Для SPA:

Тип файла Рекомендуемый размер
Initial JS 150–300 kB gzip
Vendor chunk до 500 kB gzip
CSS до 100 kB gzip

Для мобильных приложений требования обычно строже.


Пример полноценной конфигурации анализа

import { defineConfig } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig(({ mode }) => ({
  build: {
    sourcemap: true,
    chunkSizeWarningLimit: 700,
    rollupOptions: {
      output: {
        manualChunks: {
          react: ['react', 'react-dom'],
          charts: ['chart.js'],
          editor: ['monaco-editor']
        }
      }
    }
  },

  plugins: [
    mode === 'analyze'
      ? visualizer({
          open: true,
          gzipSize: true,
          brotliSize: true,
          filename: 'stats.html'
        })
      : null
  ]
}))

Ключевые признаки хорошо оптимизированного bundle

  • небольшой initial chunk;
  • lazy loading страниц;
  • разделённый vendor;
  • отсутствие duplicated packages;
  • корректный tree shaking;
  • минимальный CSS;
  • эффективное gzip/brotli-сжатие;
  • отсутствие гигантских shared chunks;
  • стабильное кеширование;
  • predictable chunk structure.