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.

Связанные темы

Ресурсы