Webpack
Зачем нужно
Webpack — модульный сборщик (bundler) для JavaScript-приложений. Он берёт все файлы проекта (JS, CSS, изображения, шрифты) и превращает их в оптимизированные бандлы для браузера. Webpack решает проблему модульности: браузер не понимает import/export, сотни файлов, npm-пакеты — Webpack собирает всё в один или несколько файлов.
Где используется
- Сборка SPA (React, Vue, Angular проекты)
- Код с ES-модулями, TypeScript, JSX, SCSS
- Оптимизация для production (минификация, tree shaking)
- Разработка с hot reload (dev server)
Основные концепции
Entry → Loaders → Plugins → Output
src/index.js ──→ babel-loader ──→ HtmlWebpackPlugin ──→ dist/bundle.js
src/style.css ─→ css-loader ───→ MiniCssExtract ─────→ dist/style.css
src/logo.png ──→ file-loader ──→ CopyPlugin ─────────→ dist/logo.png
Entry (точка входа)
// webpack.config.js
module.exports = {
// Откуда начинать сборку
entry: './src/index.js',
// Несколько точек входа
// entry: {
// app: './src/app.js',
// admin: './src/admin.js',
// },
};
Output (выход)
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
// Куда складывать результат
path: path.resolve(__dirname, 'dist'),
// Имя файла ([name] = имя entry, [contenthash] = хеш содержимого)
filename: '[name].[contenthash].js',
// Очищать dist перед сборкой
clean: true,
},
};
Mode (режим)
module.exports = {
// 'development' — быстрая сборка, source maps, без минификации
// 'production' — минификация, tree shaking, оптимизации
mode: 'production',
};
Loaders (загрузчики)
Webpack из коробки понимает только JS и JSON. Loaders учат его обрабатывать другие типы файлов:
module.exports = {
module: {
rules: [
// JavaScript/JSX через Babel
{
test: /\.jsx?$/, // Regex — какие файлы
exclude: /node_modules/, // Исключения
use: 'babel-loader', // Какой loader
},
// CSS
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
// Порядок СПРАВА → НАЛЕВО:
// 1. css-loader — разбирает CSS, обрабатывает import
// 2. style-loader — вставляет CSS в <style> тег
},
// Изображения (встроенная поддержка Webpack 5)
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource',
},
// Шрифты
{
test: /\.(woff|woff2|eot|ttf)$/,
type: 'asset/resource',
},
],
},
};
Plugins (плагины)
Plugins расширяют возможности Webpack на этапе сборки:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
// Генерирует HTML с подключёнными бандлами
new HtmlWebpackPlugin({
template: './src/index.html',
}),
// Извлекает CSS в отдельный файл
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
};
Полный конфиг
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (env, argv) => {
const isDev = argv.mode === 'development';
return {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: isDev ? '[name].js' : '[name].[contenthash].js',
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
],
},
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024, // <8kb → inline base64
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
!isDev && new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
].filter(Boolean),
devServer: {
port: 3000,
hot: true, // Hot Module Replacement
historyApiFallback: true, // SPA routing
open: true, // Открыть браузер
},
devtool: isDev ? 'eval-source-map' : 'source-map',
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
};
};
Dev Server
# Установка
npm install --save-dev webpack-dev-server
# Запуск
npx webpack serve --mode development
// package.json
{
"scripts": {
"dev": "webpack serve --mode development",
"build": "webpack --mode production",
"build:analyze": "webpack --mode production --env analyze"
}
}
Code Splitting
Разделение бандла на части для ленивой загрузки:
// === Динамический import ===
// Webpack автоматически создаёт отдельный chunk
button.addEventListener('click', async () => {
// chart.js загрузится только по клику
const { Chart } = await import('./chart.js');
new Chart(data);
});
// === Именование chunks ===
const module = await import(
/* webpackChunkName: "chart" */
'./chart.js'
);
// === SplitChunks — общий код в отдельный файл ===
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // Выделить общие модули
cacheGroups: {
vendor: {
test: /node_modules/,
name: 'vendors',
chunks: 'all',
},
},
},
},
};
Tree Shaking
Удаление неиспользуемого кода:
// utils.js
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
export function divide(a, b) { return a / b; }
// index.js — используем только add
import { add } from './utils.js';
console.log(add(1, 2));
// В production бандле multiply и divide будут УДАЛЕНЫ
// Условия: ES-модули (import/export), mode: 'production'
// package.json — подсказка Webpack что модуль "чистый"
{
"sideEffects": false
// или указать файлы с побочными эффектами:
// "sideEffects": ["*.css", "./src/polyfills.js"]
}
Частые ошибки
- Не ставят
mode— по умолчаниюproduction, но без явного указания Webpack предупреждает - Порядок loaders —
use: ['style-loader', 'css-loader']— выполняется СПРАВА→НАЛЕВО - Нет
contenthashв production — браузер кэширует старые файлы, пользователь видит устаревший код - Не исключают node_modules — babel-loader обрабатывает зависимости (медленно и не нужно)
- Всё в одном бандле — нет code splitting, пользователь загружает весь код сразу
- CommonJS вместо ESM — tree shaking не работает с
require/module.exports
Практика
- Настроить Webpack с нуля: entry, output, babel-loader, css-loader
- Добавить HtmlWebpackPlugin и dev server
- Реализовать code splitting с динамическим
import - Настроить splitChunks для выделения vendor-бандла
- Проанализировать бандл с webpack-bundle-analyzer
Связанные темы
- Webpack loaders — подробно о загрузчиках
- Webpack plugins — подробно о плагинах
- Vite — альтернативный сборщик
- Что такое SPA — SPA-приложения собираются через Webpack