Механизм загрузчиков в Webpack предполагает обработку каждого модуля
через цепочку трансформаций. При росте проекта эта обработка может
становиться значительной по времени, особенно если одни и те же правила
применяются ко всем файлам без ограничений. Для управления
производительностью и предсказуемостью сборки используется сужение
области применения загрузчиков через параметры include и
exclude.
Каждый загрузчик в Webpack может быть ограничен набором файлов, к которым он применяется. Это реализуется через проверку пути к модулю:
include задаёт набор директорий или файлов, которые
разрешены для обработкиexclude задаёт набор директорий или файлов, которые
исключаются из обработкиОба параметра могут использоваться как отдельно, так и совместно, но их комбинация требует понимания приоритета и логики фильтрации.
Внутренняя логика проверки упрощённо выглядит следующим образом:
excludeincludeinclude, загрузчик
применяетсяФактически Webpack использует функции-предикаты для определения попадания модуля в область обработки.
Параметры include и exclude принимают
несколько типов значений:
test (например, RegExp)Пример использования строкового пути:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: '/src',
loader: 'babel-loader'
}
]
}
};
В этом случае загрузчик применяется только к файлам внутри директории
src.
Использование массива путей:
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'shared')
]
Такой подход позволяет расширять зону обработки без дублирования правил.
Регулярные выражения дают более гибкий контроль:
include: /src\/(components|utils)/
Это позволяет ограничить обработку только определёнными подпапками.
Функциональный вариант:
include: (filepath) => filepath.includes('src')
Такой способ используется реже, но даёт максимальную гибкость.
На практике важным аспектом является взаимодействие
include и exclude. Если оба параметра заданы
одновременно, исключения обычно имеют более высокий приоритет в типовых
конфигурациях сборок.
Пример:
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
loader: 'babel-loader'
}
Здесь:
node_modules исключаются независимо от
includesrc обрабатываются только JS-файлы, не попадающие
под excludeТакая конфигурация является стандартной, так как
node_modules почти всегда исключается из транспиляции.
Основная причина использования include и
exclude — оптимизация времени сборки. Без ограничения
области обработки загрузчик вынужден анализировать каждый модуль
проекта, включая сторонние зависимости.
Наиболее критичные случаи:
Каждый лишний файл увеличивает время работы пайплайна.
Ограничение области обработки позволяет:
Наиболее распространённый шаблон:
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
Идея заключается в том, что зависимости уже поставляются в транспилированном виде, либо совместимы с целевыми окружениями.
Более строгий и контролируемый вариант:
{
test: /\.ts$/,
include: path.resolve(__dirname, 'src'),
use: 'ts-loader'
}
Такой подход исключает случайную обработку файлов вне исходного кода приложения.
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /legacy/,
use: 'babel-loader'
}
Здесь создаётся дополнительный слой фильтрации внутри проекта.
В реальных проектах часто возникает необходимость более точной настройки, чем просто include/exclude по папкам.
{
test: /\.js$/,
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'packages/ui')
],
exclude: /node_modules/,
use: 'babel-loader'
}
Это характерно для монорепозиториев, где код разделён на пакеты.
exclude: [
path.resolve(__dirname, 'src/__tests__'),
path.resolve(__dirname, 'src/mock')
]
Такой подход позволяет исключить тестовые и вспомогательные файлы из производственной сборки.
exclude: (filepath) => {
return filepath.includes('__tests__') || filepath.endsWith('.spec.js');
}
Функции применяются, когда структура проекта динамическая или сложная для выражения через RegExp.
Одной из распространённых проблем является чрезмерное ограничение области обработки.
Типичный случай:
include: path.resolve(__dirname, 'src/components')
При таком ограничении код вне components не
обрабатывается, что может привести к:
Другой частый случай — дублирование логики:
include: /src/,
exclude: /src/
Такая конфигурация фактически делает правило неработоспособным.
Также ошибкой является отсутствие исключения
node_modules при использовании Babel, что приводит к
значительному замедлению сборки.
Хотя include и exclude задаются внутри
конкретного rule, общий порядок правил в конфигурации Webpack также
влияет на результат.
Если один и тот же файл попадает под несколько правил, каждое из них
может применяться последовательно, если не ограничено через
oneOf или enforce.
Пример конфликтной конфигурации:
rules: [
{
test: /\.js$/,
include: /src/,
loader: 'babel-loader'
},
{
test: /\.js$/,
include: /src/,
loader: 'eslint-loader'
}
]
Оба загрузчика будут применены к одним и тем же файлам, что не всегда является желаемым поведением.
В больших проектах применение include/exclude становится частью общей стратегии оптимизации сборки. Вместо глобальных правил используется точечное распределение зон ответственности:
Такой подход снижает стоимость пересборки и делает поведение конфигурации предсказуемым.
Особенно эффективно это проявляется при использовании кеширования загрузчиков, где объём входных файлов напрямую влияет на эффективность кеша.
Сужение области обработки тесно связано с механизмом разрешения модулей. Webpack сначала определяет модуль, затем применяет к нему правила.
Это означает, что:
Поэтому файл может быть доступен в проекте, но не проходить через определённый загрузчик, что иногда используется намеренно для оптимизации.
Правильное использование include/exclude фактически формирует границы архитектуры сборки. Через них определяется:
В крупных приложениях эти параметры становятся частью стандарта кодовой базы и фиксируются в базовых конфигурациях сборщика.