Всё началось невинно. Нужен debounce для поиска — поставил Lodash. Нужно форматировать даты — Moment.js. Иконки? React Icons, конечно.
Через три месяца разработки делаю
npm run build и вижу:⚠️ 2.8 MB main.js
Решил разобраться. Установил webpack-bundle-analyzer и офигел от того, что увидел.
Оказалось, я тащил в проект кучу лишнего:
Lodash (70 KB)
Импортировал всю библиотеку ради двух функций. Остальные 200+ методов просто висят мёртвым грузом.
Moment.js (70 KB)
Мне нужен был толькоformat('DD.MM.YYYY'), а получил все локали мира, парсеры timezone и calendar-системы.
React Icons
По проекту набралось 50+ импортов разных иконок. Bundle незаметно разросся.
Картинки в bundle
Webpack превращал изображения в base64 и пихал прямо в JavaScript. Hero-картинка на 200 KB стала частью main.js.
Начал с простого — заменил импорты на точечные:
// Было: тащит 70 KB
import _ from 'lodash'
// Стало: всего 1-2 KB
import debounce from 'lodash/debounce'
Дальше пошёл по библиотекам и нашёл более лёгкие альтернативы:
Moment.js (70 KB) → date-fns (11 KB)
Axios (13 KB) → fetch API (нативно)
Для роутинга включил code splitting. Теперь страницы грузятся только когда пользователь на них переходит:
const Dashboard = lazy(() => import('./Dashboard'))
const Settings = lazy(() => import('./Settings'))
<Suspense fallback={<Loader />}>
<Dashboard />
</Suspense>
С картинками разобрался так: большие файлы переложил в
/public, конвертнул в WebP (экономия 30-50%), добавил loading="lazy".И последнее — настроил size-limit в CI/CD. Теперь если кто-то попытается влить PR с раздутым bundle, пайплайн упадёт:
"size-limit": [{
"path": "build/static/js/*.js",
"limit": "500 KB"
}]
Было:
• Bundle: 2.8 MB
• Загрузка на 3G: 8.5 секунд
• Lighthouse: 45/100
Стало:
• Main bundle: 380 KB
• Остальное в lazy chunks по 50-150 KB
• Загрузка на 3G: 1.2 секунды
• Lighthouse: 92/100
Сайт стал грузиться в 7 раз быстрее. Пользователи перестали жаловаться. Менеджер доволен.
Главная ошибка была в подходе. Я думал: «npm install — и готово, пакеты же для этого и есть!»
Но каждый килобайт в bundle — это реальное время загрузки. Особенно для людей не на оптоволокне.
У меня на MacBook сайт грузился моментально. А у пользователя с iPhone 8 в метро на 3G — 10 секунд чёрного экрана. Это разные миры.
Теперь перед каждым
npm install спрашиваю себя: мне правда нужна вся библиотека? Или хватит одной функции? Может, это вообще можно сделать нативно?И раз в спринт запускаю
npm run build && npm run analyze. Лучше увидеть проблему сейчас, чем в жалобах пользователей потом.#code_battle
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🥱3🥰2
Что обычно раздувает bundle в твоих проектах ❓
Anonymous Poll
39%
Тяжёлые библиотеки (Moment.js, Lodash целиком)
19%
UI-киты (Material-UI, Ant Design)
14%
Картинки и медиа (неоптимизированные изображения, видео, шрифты)
24%
Избыточные зависимости (неиспользуемый код, дубликаты пакетов, старые версии)
4%
State management и утилиты (Redux + middleware, форм-библиотеки, анимации)
🥰2