Загрузчики в Webpack представляют собой цепочки функций преобразования модулей, через которые проходит каждый импортируемый файл. Производительность всей сборки часто определяется не бандлером как таковым, а именно временем выполнения loader-цепочек.
Медленные загрузчики возникают по трём основным причинам:
Тяжёлые преобразования
Избыточная область применения
include /
excludenode_modules, хотя это не требуетсяОтсутствие кэширования и параллелизма
Понимание этих причин определяет дальнейшую стратегию диагностики.
Диагностика начинается с измерения, а не предположений. Основные индикаторы:
Время полной сборки
Долгие rebuild-циклы
Неравномерная нагрузка
Webpack предоставляет встроенные механизмы анализа.
Генерация подробного отчёта:
webpack --profile --json > stats.json
Далее анализируется:
В stats.json ключевыми являются:
modules[].profilemodules[].loadersbuiltAt, endTimeПо ним выявляется:
Один из самых прямых способов диагностики:
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
// webpack config
});
Он позволяет увидеть:
Особенность: измерения могут слегка искажать реальность из-за обёртки, но для выявления узких мест этого достаточно.
Большинство проблем возникает в конфигурации, а не в самих инструментах.
Проблемная конфигурация:
{
test: /\.js$/,
loader: "babel-loader"
}
Исправленная версия:
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
loader: "babel-loader"
}
Webpack выполняет loaders справа налево:
use: ["style-loader", "css-loader", "sass-loader"]
Ошибки порядка приводят к:
Самый частый источник замедлений.
Причины:
@babel/preset-env без
target)node_modulesОптимизация:
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
Ключевые стратегии:
Основная проблема — двойная работа.
Плохой вариант:
ts-loader + проверка типов + BabelОптимизация:
{
loader: "ts-loader",
options: {
transpileOnly: true
}
}
Дополнительно:
ForkTsCheckerWebpackPluginПроблема TypeScript заключается в том, что полноценная типизация блокирует поток сборки.
Цепочка часто выглядит так:
use: [
"style-loader",
"css-loader",
"sass-loader"
]
Проблемы:
Узкие места:
@import вместо @useСтарые подходы:
file-loaderurl-loaderWebpack 5 заменяет их на asset modules:
{
test: /\.(png|jpg|svg)$/,
type: "asset"
}
Проблемы старых loader’ов:
Webpack 5 включает встроенный filesystem cache:
cache: {
type: "filesystem"
}
Эффект:
Ошибки:
Позволяет выполнять loader’ы в воркерах:
use: [
"thread-loader",
"babel-loader"
]
Особенности:
Не все задачи выгодно распараллеливать:
Некоторые режимы source map значительно увеличивают время:
eval-source-map — быстрый dev, но не всегда
стабильныйsource-map — медленный production вариантПроблемы:
Диагностика:
devtoolTerser и другие минификаторы могут конкурировать с loader’ами за ресурсы.
optimization: {
minimize: true
}
Проблемы:
Оптимизации:
Практический метод выявления узкого места:
Webpack часто случайно обрабатывает:
Решение:
exclude: /node_modules/
или точечное включение:
include: path.resolve(__dirname, "src")
Иногда проблема не в loader’ах, а в архитектуре:
Процесс диагностики обычно строится по слоям:
Каждый слой устраняет один класс проблем, но реальный прирост достигается только при комбинации оптимизаций loader-цепочек, кеширования и ограничения области обработки файлов.