Что такое сборщик (bundler) и чем Webpack отличается от Vite?
Вопрос
Что делает сборщик (bundler) и в чём принципиальная разница между Webpack и Vite?
Короткий ответ
Сборщик анализирует граф зависимостей проекта (import/require), применяет к модулям трансформации (Babel/TS/CSS-загрузчики) и собирает их в один или несколько оптимизированных бандлов. Webpack всегда собирает бандл перед запуском dev-сервера, а Vite в разработке отдаёт исходные ES-модули браузеру напрямую, поэтому стартует почти мгновенно.
Подробный ответ
Задача любого бандлера сводится к четырём вещам:
- Резолвинг модулей — построение графа зависимостей, начиная с entry-файлов.
- Трансформации — прогон файлов через loaders/plugins: TS → JS, SCSS → CSS, JSX → JS и т.д.
- Code-splitting — разбиение графа на чанки (по роутам, по
import()), чтобы не грузить всё приложение сразу. - Оптимизация вывода — tree shaking, минификация, хэширование имён файлов для кэширования.
Webpack появился раньше остальных и решает всё это через единый конвейер loaders/plugins. Даже в dev-режиме он должен построить полный (или почти полный) бандл перед тем, как отдать что-то браузеру — на больших проектах это секунды и десятки секунд на старте и при hot reload. Зато у него самая зрелая экосистема плагинов и максимальная гибкость конфигурации.
Vite меняет подход именно для разработки: он не бандлит приложение целиком. Браузеры давно умеют нативно грузить ES-модули (<script type="module">), поэтому Vite отдаёт файлы по запросу — модуль запросили, Vite на лету его трансформировал (через esbuild, написанный на Go, что в 10–100 раз быстрее JS-трансформеров) и отдал. Тяжёлые зависимости из node_modules (react, lodash и т.д.) Vite заранее один раз "предбандлит" тем же esbuild в CommonJS→ESM, чтобы не делать сотни отдельных HTTP-запросов на внутренние файлы пакета. Отсюда почти мгновенный старт dev-сервера независимо от размера приложения.
Для продакшен-сборки Vite не использует нативные ESM-импорты браузера (слишком много запросов в проде), а под капотом собирает бандл через Rollup — то есть в проде Vite тоже делает полноценный бандлинг, просто с другим инструментом, заточенным на маленький и чистый output.
Отдельно стоят esbuild и Turbopack (от Vercel, на Rust) — сборщики нового поколения, написанные на компилируемых языках вместо JS, за счёт чего трансформации и парсинг на порядок быстрее. Их часто используют не как замену Webpack/Vite целиком, а как ускоряющий слой внутри других инструментов.
Пример
// vite.config.js — минимальная конфигурация
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
// прод-сборка идёт через Rollup под капотом
rollupOptions: {
output: {
// ручной code-splitting для тяжёлых вендорных библиотек
manualChunks: {
vendor: ['vue', 'vue-router'],
},
},
},
},
})
// webpack.config.js — для сравнения тот же смысл в Webpack
module.exports = {
entry: './src/main.js',
optimization: {
splitChunks: { chunks: 'all' }, // аналог manualChunks
},
module: {
rules: [{ test: /\.vue$/, loader: 'vue-loader' }],
},
}
Дополнительные вопросы
- Почему Vite использует esbuild в dev и Rollup в проде, а не esbuild везде?
- Что такое tree shaking и при каких условиях он не срабатывает (например, из-за side-эффектов в модуле)?
- Как работает HMR (Hot Module Replacement) и чем он отличается от полной перезагрузки страницы?