Механизм применения загрузчиков в Webpack основан на строгом порядке их выполнения, который напрямую влияет на итоговую обработку модулей. Ошибочное понимание этого порядка приводит к некорректной трансформации кода, неожиданным результатам сборки и трудноуловимым багам.
Webpack применяет загрузчики как последовательность функций, где
каждый следующий loader получает результат работы предыдущего. Эта
цепочка формируется в конфигурации правила
module.rules.
Ключевой принцип:
загрузчики выполняются справа налево (right-to-left)
Это означает, что последний loader в массиве вызывается первым.
Пример:
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
Фактический порядок выполнения будет следующим:
postcss-loadercss-loaderstyle-loaderWebpack строит цепочку в виде композиции функций, аналогичной:
styleLoader(cssLoader(postcssLoader(input)))
Каждый loader оборачивает результат предыдущего, поэтому выполнение происходит изнутри наружу.
Это поведение обусловлено архитектурой потоковой обработки модулей:
Помимо горизонтального порядка внутри массива use,
существует вертикальный порядок применения правил в
module.rules.
Webpack проходит по массиву правил сверху вниз, но применяет только те loaders, чьи условия совпали.
Однако внутри одного совпавшего правила действует обратная логика:
rules → сверху вниз (поиск подходящего
rule)use → справа налево (применение loaders)module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
Webpack:
.js).css)Цепочки могут быть значительно сложнее:
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
},
'postcss-loader',
'sass-loader'
]
Фактический порядок:
sass-loader — преобразует SCSS/SASS в CSSpostcss-loader — постобработка (автопрефиксы,
плагины)css-loader — интерпретация @import и
url()style-loader — внедрение стилей в DOMWebpack loaders могут содержать два типа фаз:
И здесь порядок становится ещё сложнее:
Если loaders имеют pitch-методы, Webpack сначала
проходит по ним:
use: ['a-loader', 'b-loader', 'c-loader']
Порядок pitch-фазы:
a-loader.pitchb-loader.pitchc-loader.pitchПосле pitch-фазы:
c-loaderb-loadera-loaderPitch loader может вернуть значение, и тогда дальнейшая цепочка normal loaders не выполняется.
module.exports.pitch = function (remainingRequest) {
return "export default 'cached result'";
};
В этом случае:
Это позволяет реализовывать кэширование и оптимизации на уровне загрузчиков.
Неправильное расположение loaders может привести к критическим ошибкам:
use: ['css-loader', 'style-loader']
Проблема:
css-loader возвращает JS-модульstyle-loader ожидает CSS-строкуИтог: некорректная интерпретация и падение сборки
use: ['style-loader', 'css-loader']
Удобная ментальная модель:
use читается как список этапов сборкиМожно представить так:
input → loader3 → loader2 → loader1 → output
где loader3 стоит последним в массиве.
Правильная организация порядка позволяет разделять ответственность:
Каждый этап должен быть строго на своём месте в цепочке.
Webpack позволяет дополнительно управлять порядком через
enforce:
rules: [
{
test: /\.js$/,
use: ['eslint-loader'],
enforce: 'pre'
},
{
test: /\.js$/,
use: ['babel-loader']
}
]
Порядок становится:
eslint-loader (pre)babel-loader (normal)Существует также:
enforce: 'post' — выполняется после всех обычных
loadersИтоговая система приоритета:
enforce: pre — сверху приоритетenforce: post — выполняется последнимДля анализа сложных конфигураций удобно мысленно разворачивать цепочку:
use: [
'loader-a',
'loader-b',
'loader-c'
]
в:
loader-c → loader-b → loader-a
И затем учитывать:
SASS после CSS loader
Babel после Webpack asset loader
style-loader в начале цепочки
Порядок loaders в Webpack — это не просто массив конфигурации, а строго определённая модель композиции функций, где: