Переход с Webpack 4 на пятую версию затрагивает не только конфигурацию, но и внутреннюю модель работы сборщика. Webpack 5 был переработан с акцентом на:
Основная сложность миграции заключается в том, что многие изменения являются не синтаксическими, а концептуальными.
Webpack 5 требует:
Типичная установка:
npm install webpack@5 webpack-cli@4 --save-dev
Для dev server:
npm install webpack-dev-server@4 --save-dev
В Webpack 4 CLI часто устанавливался неявно или использовались устаревшие команды.
Webpack 5 требует отдельный пакет:
npm install webpack-cli --save-dev
Старые команды:
webpack-dev-server
Заменяются на:
webpack serve
Пример package.json:
{
"scripts": {
"build": "webpack",
"start": "webpack serve --mode development"
}
}
Webpack 5 строже относится к параметру mode.
Конфигурация:
module.exports = {
mode: 'production'
};
Без mode Webpack выводит предупреждение.
Доступные режимы:
Одно из главных нововведений Webpack 5 — файловый кэш сборки.
В Webpack 4 кэш в основном находился в памяти процесса. После перезапуска сборка начиналась заново.
Webpack 5 умеет сохранять кэш на диск:
module.exports = {
cache: {
type: 'filesystem'
}
};
Преимущества:
Дополнительная настройка:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
}
};
Это наиболее болезненное изменение при миграции.
Webpack 4 автоматически подключал polyfill для:
Даже браузерные проекты могли случайно использовать Node.js API.
Автоматические polyfill удалены.
Ошибка:
Module not found: Error: Can't resolve 'crypto'
означает, что пакет зависит от Node.js API.
Теперь polyfill подключаются явно.
Установка:
npm install crypto-browserify stream-browserify buffer process --save
Конфигурация:
const webpack = require('webpack');
module.exports = {
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify')
}
},
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser'
})
]
};
Если модуль не нужен в браузере:
module.exports = {
resolve: {
fallback: {
fs: false,
path: false
}
}
};
Это особенно важно для backend-oriented библиотек.
Webpack 5 встроил обработку ресурсов напрямую в ядро.
module.exports = {
module: {
rules: [
{
test: /\.png$/,
use: ['file-loader']
}
]
}
};
module.exports = {
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource'
}
]
}
};
Создаёт отдельный файл.
{
test: /\.png$/,
type: 'asset/resource'
}
Встраивает Base64 в bundle.
{
test: /\.svg$/,
type: 'asset/inline'
}
Импортирует содержимое как строку.
{
test: /\.txt$/,
type: 'asset/source'
}
Автоматический выбор между inline и resource.
{
test: /\.(png|jpg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
}
}
Webpack 5 улучшил механизм разделения чанков.
optimization: {
splitChunks: {
chunks: 'all'
}
}
Базовая конфигурация сохраняется, но изменились:
Рекомендуется выделять runtime отдельно:
optimization: {
runtimeChunk: 'single'
}
Это улучшает долгосрочное кэширование.
Webpack 4 часто генерировал нестабильные идентификаторы модулей.
Webpack 5 использует deterministic ids.
optimization: {
moduleIds: 'deterministic',
chunkIds: 'deterministic'
}
Преимущества:
Ранее часто использовалось:
new CleanWebpackPlugin()
Webpack 5 поддерживает встроенную очистку:
module.exports = {
output: {
clean: true
}
};
Это позволяет удалить сторонний plugin.
devServer: {
contentBase: './dist'
}
contentBase удалён.
Используется:
devServer: {
static: './dist'
}
Старый способ:
devServer: {
hot: true,
hotOnly: true
}
Новый вариант:
devServer: {
hot: true
}
hotOnly удалён.
Webpack 4:
node: {
fs: 'empty'
}
Webpack 5:
resolve: {
fallback: {
fs: false
}
}
Секция node практически больше не используется.
Webpack 5 поддерживает новые target.
Пример:
module.exports = {
target: 'web'
};
Другие варианты:
Webpack 5 значительно улучшил ESM.
{
"type": "module"
}
export default {
mode: 'production'
};
Webpack 5 строже относится к ESM-импортам.
Ошибка:
Can't resolve './utils'
может появляться из-за отсутствия расширения.
Решение:
resolve: {
fullySpecified: false
}
Либо:
import './utils.js';
Webpack 5 лучше анализирует:
Рекомендуется явно указывать:
{
"sideEffects": false
}
или:
{
"sideEffects": [
"*.css"
]
}
Одно из крупнейших нововведений Webpack 5.
Позволяет динамически подключать модули между независимыми приложениями.
Пример:
const ModuleFederationPlugin =
require('webpack').container.ModuleFederationPlugin;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
shop: 'shop@http://localhost:3001/remoteEntry.js'
}
})
]
};
Webpack 5 изменил генерацию hash.
Новые варианты:
output: {
filename: '[name].[contenthash].js'
}
contenthash предпочтительнее hash.
Рекомендуемые режимы:
devtool: 'eval-cheap-module-source-map'
devtool: 'source-map'
Некоторые legacy-варианты deprecated.
Старые loader могут перестать работать.
Особенно проблемны:
Часто требуется обновление:
npm install babel-loader@latest css-loader@latest style-loader@latest --save-dev
Webpack 5 лучше работает с современными preset.
Пример:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env'
]
}
}
}
]
}
Старые версии plugin несовместимы.
Требуется:
npm install mini-css-extract-plugin@latest --save-dev
Webpack 5 уже включает terser.
Часто отдельная настройка больше не нужна.
Webpack 5 оптимизировал file watching.
Новая конфигурация:
watchOptions: {
ignored: /node_modules/
}
Webpack 5 поддерживает ленивую компиляцию.
experiments: {
lazyCompilation: true
}
Особенно полезно для больших dev-сборок.
Новая возможность:
const data = await fetch('/api/data');
Включение:
experiments: {
topLevelAwait: true
}
Webpack 5 ввёл систему экспериментальных возможностей.
experiments: {
outputModule: true
}
Генерация ESM bundle:
output: {
module: true
},
experiments: {
outputModule: true
}
Автоматический publicPath:
output: {
publicPath: 'auto'
}
Webpack сам определяет путь загрузки chunk.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
devServer: {
contentBase: './dist',
hot: true
},
module: {
rules: [
{
test: /\.png$/,
use: ['file-loader']
}
]
}
};
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
cache: {
type: 'filesystem'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
publicPath: 'auto'
},
devServer: {
static: './dist',
hot: true
},
optimization: {
moduleIds: 'deterministic',
chunkIds: 'deterministic',
runtimeChunk: 'single'
},
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource'
}
]
},
plugins: [
new HtmlWebpackPlugin()
]
};
Причина:
Решение:
Ошибка:
Must use import to load ES Module
Причина:
Ошибка:
this.getOptions is not a function
Причина:
После миграции могут измениться:
Это связано с новым deterministic algorithm.
Обновление зависимостей:
Удаление deprecated API:
Включение новых возможностей:
Проверка production bundle:
Webpack 5 обычно даёт:
На крупных проектах ускорение rebuild может достигать нескольких раз благодаря filesystem cache и новой системе графа модулей.