После выполнения сборки Webpack формирует набор файлов, называемый
выходным бандлом. По умолчанию результат помещается в каталог
dist. Именно эта директория обычно отправляется на
production-сервер или используется в качестве статических ресурсов
приложения.
Типичная структура после сборки:
project/
├── src/
│ ├── index.js
│ ├── components/
│ └── styles/
├── dist/
│ ├── main.js
│ └── index.html
├── package.json
└── webpack.config.js
Каталог src содержит исходный код, а dist —
итоговые оптимизированные файлы.
Выходной бандл — это результат объединения модулей, зависимостей, стилей и ресурсов в один или несколько файлов.
Webpack анализирует граф зависимостей:
index.js
├── utils.js
├── app.js
│ └── api.js
└── style.css
После обработки формируется единый файл:
main.js
или набор файлов:
runtime.js
vendors.js
main.js
Внутри этих файлов уже находятся все необходимые модули приложения.
outputСтруктура выходного бандла управляется через раздел
output.
Пример:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
}
};
| Параметр | Назначение |
|---|---|
filename |
Имя выходного файла |
path |
Абсолютный путь к каталогу сборки |
publicPath |
Базовый URL для ресурсов |
clean |
Очистка каталога перед сборкой |
assetModuleFilename |
Структура файлов ресурсов |
filenameОпределяет имя итогового JavaScript-бандла.
output: {
filename: 'bundle.js'
}
Результат:
dist/
└── bundle.js
Webpack поддерживает специальные плейсхолдеры.
[name]Имя entry-point.
entry: {
app: './src/app.js',
admin: './src/admin.js'
},
output: {
filename: '[name].js'
}
Результат:
dist/
├── app.js
└── admin.js
[id]Уникальный идентификатор чанка.
filename: '[id].js'
Результат:
dist/
├── 123.js
└── 456.js
Используется редко, поскольку имена становятся нечитаемыми.
[hash]Общий hash всей сборки.
filename: '[name].[hash].js'
Результат:
main.a6f4d8c.js
При любом изменении проекта hash меняется.
[contenthash]Hash конкретного содержимого файла.
filename: '[name].[contenthash].js'
Наиболее популярный вариант для production.
Пример:
dist/
├── main.12fa7c.js
├── vendors.98ab44.js
└── styles.4d9911.css
Если изменился только CSS, JavaScript-файлы сохранят прежний hash.
Это критически важно для кэширования браузером.
pathWebpack требует абсолютный путь.
Правильный вариант:
const path = require('path');
output: {
path: path.resolve(__dirname, 'dist')
}
Неправильный вариант:
output: {
path: './dist'
}
Webpack выдаст ошибку:
The provided value "./dist" is not an absolute path
Без очистки старые файлы могут оставаться внутри
dist.
Пример проблемы:
dist/
├── old.bundle.js
├── main.js
└── vendor.js
Для автоматической очистки используется:
output: {
clean: true
}
Webpack удалит старое содержимое перед новой сборкой.
Webpack может разбивать приложение на отдельные части — чанки.
Пример:
import('./dashboard');
После сборки:
dist/
├── main.js
├── dashboard.js
└── vendors.js
| Чанк | Содержимое |
|---|---|
main.js |
Основная логика |
vendors.js |
Библиотеки npm |
dashboard.js |
Ленивая загрузка |
Webpack создаёт специальный runtime-код.
Он отвечает за:
Пример:
optimization: {
runtimeChunk: 'single'
}
Результат:
dist/
├── runtime.js
├── main.js
└── vendors.js
Webpack умеет автоматически выделять сторонние библиотеки.
Настройка:
optimization: {
splitChunks: {
chunks: 'all'
}
}
Результат:
dist/
├── vendors-node_modules_react_index_js.js
├── main.js
└── runtime.js
Типичная production-сборка:
dist/
├── js/
│ ├── runtime.a1b2.js
│ ├── vendors.f3e4.js
│ └── main.98cd.js
│
├── css/
│ └── main.12aa.css
│
├── images/
│ ├── logo.7d1f.png
│ └── bg.1ac4.jpg
│
└── fonts/
└── roboto.91ef.woff2
distWebpack позволяет формировать собственную структуру.
Пример:
output: {
filename: 'js/[name].[contenthash].js'
}
Результат:
dist/
└── js/
├── main.js
└── admin.js
Для изображений, шрифтов и SVG применяется
assetModuleFilename.
output: {
assetModuleFilename: 'assets/[hash][ext][query]'
}
Результат:
dist/
└── assets/
├── a7f3.png
├── b22f.svg
└── c8d1.woff2
Более удобная структура:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash][ext]'
}
},
{
test: /\.(woff2|ttf)$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash][ext]'
}
}
]
}
};
Результат:
dist/
├── images/
│ └── logo.abc123.png
│
└── fonts/
└── roboto.def456.woff2
publicPathpublicPath определяет URL, по которому браузер получает
ресурсы.
Пример:
output: {
publicPath: '/static/'
}
Тогда:
main.js
будет загружаться как:
/static/main.js
publicPath часто применяется для CDN.
output: {
publicPath: 'https://cdn.example.com/assets/'
}
Файлы будут подключаться:
https://cdn.example.com/assets/main.js
publicPathWebpack поддерживает автоматическое определение:
output: {
publicPath: 'auto'
}
Это полезно при:
При включении source maps:
devtool: 'source-map'
Webpack создаёт:
dist/
├── main.js
└── main.js.map
Файл .map содержит соответствие между минифицированным
кодом и исходниками.
Пример проекта:
import('./profile');
import('./settings');
Результат:
dist/
├── main.js
├── profile.chunk.js
├── settings.chunk.js
└── runtime.js
Без имени:
import('./dashboard');
Webpack создаёт:
432.js
С именем:
import(
/* webpackChunkName: "dashboard" */
'./dashboard'
);
Результат:
dashboard.js
Development-бандл обычно:
Пример:
dist/
├── main.js
├── vendors.js
└── main.js.map
Production-бандл:
Пример:
dist/
├── runtime.f13a.js
├── vendors.7bc1.js
├── main.22ef.js
└── main.22ef.js.LICENSE.txt
Webpack может автоматически выносить лицензии.
Пример:
main.js.LICENSE.txt
Там находятся лицензии библиотек:
React
MIT License
Lodash
MIT License
Webpack удаляет неиспользуемый код.
Исходный модуль:
export function a() {}
export function b() {}
export function c() {}
Использование:
import { a } from './utils';
В production-бандл попадёт только:
function a(){}
Production-режим:
mode: 'production'
Превращает:
function calculatePrice(price, tax) {
return price + tax;
}
в:
function n(n,t){return n+t}
После сборки структура может оказаться слишком большой.
Типичный пример:
dist/
├── vendors.js 2.4 MB
├── main.js 700 KB
└── charts.js 1.1 MB
Для анализа используется:
npm install webpack-bundle-analyzer --save-dev
Правильная структура позволяет:
const path = require('path');
module.exports = {
mode: 'production',
entry: {
main: './src/index.js'
},
output: {
filename: 'js/[name].[contenthash].js',
chunkFilename: 'js/[name].[contenthash].chunk.js',
assetModuleFilename: 'assets/[name].[hash][ext]',
path: path.resolve(__dirname, 'dist'),
clean: true,
publicPath: '/'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all'
}
}
};
Результирующая структура:
dist/
├── js/
│ ├── runtime.aa12.js
│ ├── vendors.bb34.js
│ ├── main.cc56.js
│ └── profile.dd78.chunk.js
│
├── assets/
│ ├── logo.ee90.svg
│ ├── hero.ff22.jpg
│ └── font.gg44.woff2
│
└── index.html