Настройка автоматической проверки размера бандла в CI/CD
Бандл растёт незаметно. Разработчик добавляет зависимость, коллега импортирует утилиту целиком вместо нужной функции — и через месяц JS-бандл весит на 200 кБ больше, чем должен. Проверка размера бандла в CI/CD останавливает это до попадания в прод.
Как это работает
Идея простая: на каждый PR или деплой собираем бандл, сравниваем его размер (и размер отдельных чанков) с baseline — значениями из предыдущего деплоя или зафиксированными лимитами. Если что-то превышает порог — CI падает или оставляет предупреждение в PR.
Инструменты делятся на два класса:
| Инструмент | Подход | Когда использовать |
|---|---|---|
bundlesize / bundlewatch |
Сравнение с фиксированными лимитами | Простые проекты, быстрая настройка |
size-limit (NEAR Protocol) |
Лимиты + анализ импортов | JS-библиотеки, пакеты npm |
| Webpack Bundle Analyzer | Визуализация, без CI-блокировки | Ручной аудит |
Vite rollup-plugin-visualizer |
То же для Vite | Ручной аудит |
| Relative CI / BuildBuddy | Сравнение PR vs base branch | Командные проекты, богатый UI |
Настройка через bundlewatch
Устанавливаем:
npm install --save-dev bundlewatch
Конфигурация в package.json:
{
"bundlewatch": {
"files": [
{ "path": "dist/assets/index-*.js", "maxSize": "150kB" },
{ "path": "dist/assets/vendor-*.js", "maxSize": "400kB" },
{ "path": "dist/assets/*.css", "maxSize": "50kB" }
],
"ci": {
"trackBranches": ["main", "master"],
"repoBranchBase": "main"
}
}
}
В GitHub Actions:
name: Bundle Size Check
on: [pull_request]
jobs:
bundlewatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- run: npx bundlewatch
env:
BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI_REPO_OWNER: ${{ github.repository_owner }}
CI_REPO_NAME: ${{ github.event.repository.name }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_BRANCH: ${{ github.head_ref }}
CI_BRANCH_BASE: ${{ github.base_ref }}
bundlewatch оставляет комментарий в PR с таблицей: текущий размер, delta, статус.
Настройка через size-limit
size-limit умеет не просто измерять, но и анализировать дерево импортов — показывает, сколько весит конкретный модуль в изоляции, учитывая tree-shaking и gzip.
npm install --save-dev size-limit @size-limit/preset-app
.size-limit.json:
[
{
"path": "dist/assets/index-*.js",
"limit": "150 kB",
"gzip": true
},
{
"name": "Vendor chunk",
"path": "dist/assets/vendor-*.js",
"limit": "380 kB",
"gzip": true
}
]
В package.json:
{
"scripts": {
"size": "size-limit",
"analyze": "size-limit --why"
}
}
--why запускает webpack-bundle-analyzer и показывает, что именно тянет размер.
Относительные лимиты вместо абсолютных
Абсолютные лимиты устаревают — проект растёт, и постоянно поднимать цифры надоедает. Альтернатива: проверять delta относительно base branch.
Скрипт сравнения размеров в CI:
#!/bin/bash
# Собираем текущую ветку
npm run build
CURRENT_SIZE=$(du -sb dist/assets/*.js | awk '{sum += $1} END {print sum}')
# Сохраняем в артефакт
echo $CURRENT_SIZE > /tmp/current_size.txt
# Загружаем размер base branch из артефактов CI
# (logic depends on CI system — здесь пример для GitHub Actions)
BASE_SIZE=$(cat /tmp/base_size.txt 2>/dev/null || echo $CURRENT_SIZE)
DELTA=$((CURRENT_SIZE - BASE_SIZE))
DELTA_PERCENT=$((DELTA * 100 / BASE_SIZE))
echo "Base: ${BASE_SIZE} bytes"
echo "Current: ${CURRENT_SIZE} bytes"
echo "Delta: ${DELTA} bytes (${DELTA_PERCENT}%)"
if [ $DELTA_PERCENT -gt 10 ]; then
echo "ERROR: Bundle grew by more than 10%"
exit 1
fi
Кеширование и ускорение
Полная пересборка на каждый PR — медленно. Кешируем node_modules и результаты Vite:
- uses: actions/cache@v4
with:
path: |
node_modules
.vite
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
На типовом проекте это сокращает время проверки с 3–4 минут до 40–60 секунд.
Что проверять помимо общего размера
- Количество чанков — рост числа чанков при code splitting может увеличить количество HTTP-запросов
- Размер initial bundle отдельно от lazy-loaded чанков — именно он влияет на LCP и TTI
- Дубли зависимостей — когда одна библиотека затягивается в несколько чанков в разных версиях
Для последнего: npm ls <package> или npx duplicate-package-checker-webpack-plugin.
Сроки внедрения
Базовая настройка bundlewatch в существующий CI-пайплайн — 4–8 часов: установка, настройка лимитов под текущие размеры, добавление шага в workflow. Настройка size-limit с анализом и уведомлениями в PR — 1–2 рабочих дня с учётом тонкой настройки лимитов по чанкам.







