Bundle vs Unbundle: разница
Bundling — сборка множества JS/CSS-модулей в один (или несколько) файлов перед отдачей браузеру; unbundled-подход (no-bundle) отдаёт модули напрямую через ESM без сборки в dev-режиме.
Зачем нужно
Понимание разницы между bundled и unbundled подходами помогает выбрать правильный инструмент и настроить pipeline. В production bundling по-прежнему необходим для оптимизации (минификация, tree-shaking, code splitting). В development unbundled-режим, который использует Vite, даёт мгновенный старт сервера и почти мгновенный HMR, потому что изменяется только один модуль, а не пересобирается весь граф.
Где используется
- Bundled: Webpack, Rollup, Parcel — production-сборка SPA
- Unbundled / ESM-first: Vite (dev-режим), Snowpack — разработческий сервер
- CDN unbundled: импорт модулей напрямую с esm.sh или unpkg в экспериментах
- Deno и современные рантаймы — работают с ESM без бандлера
Bundled vs Unbundled
BUNDLED (Webpack, традиционный подход)
────────────────────────────────────
src/ webpack dist/
index.js ──────────────────────► bundle.js (1 файл)
utils.js (разрешает граф, vendor.js
components/ минифицирует,
... tree-shaking)
Старт dev-сервера: пересобирает ВЕСЬ граф → 10-60 секунд на большом проекте
HMR: пересобирает затронутый chunk → секунды
UNBUNDLED (Vite dev-mode, ESM Native)
────────────────────────────────────
src/
index.js ──────────────────────► браузер запрашивает
utils.js (Vite трансформирует файлы по одному
components/ только запрошенный через HTTP/ESM
... модуль on-demand)
Старт dev-сервера: почти мгновенный (< 500ms)
HMR: меняется только один модуль → < 50ms
Vite: как работает ESM-first dev
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react],
// В dev: Vite сервирует src/ напрямую через ESM
// В build: использует Rollup для оптимизированного bundle
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
});
Размер bundle и tree-shaking
// Плохо — импортирует всю библиотеку lodash (70 KB+)
import _ from 'lodash';
const result = _.cloneDeep(obj);
// Хорошо — bundler вырежет только cloneDeep
import cloneDeep from 'lodash/cloneDeep';
// или через ESM-версию:
import { cloneDeep } from 'lodash-es';
| Критерий | Bundled (Webpack) | Unbundled (Vite dev) |
|---|---|---|
| Старт dev-сервера | Медленный | Мгновенный |
| HMR | Секунды | Миллисекунды |
| Production-сборка | Полная поддержка | Через Rollup |
| Tree-shaking | Да | Да (в build) |
| Поддержка браузерами | Любой | Нужен ESM (ES2020+) |
Частые ошибки
- Путают dev и prod режимы Vite — в dev Vite работает без бандлинга, в production он всё равно собирает bundle через Rollup.
- Используют Webpack в prod без Code Splitting — один огромный bundle вместо нескольких chunks по маршрутам.
- Импортируют CJS-библиотеки в unbundled-режиме — CommonJS модули не работают напрямую в браузере через ESM.
Связанные темы
- _MOC SPA
- Code Splitting -- разделение кода
- HMR -- Hot Module Replacement
- Модули -- ES Modules в браузере