Сборка фронтенд-приложений представляет собой цепочку преобразований модулей: загрузка исходников, транспиляция JavaScript/TypeScript, обработка стилей, оптимизация и бандлинг. При увеличении проекта стоимость этих операций становится критичной, особенно в режиме разработки, где пересборка запускается многократно.
Кеширование в Webpack решает задачу сокращения повторных вычислений за счёт сохранения результатов дорогостоящих операций. Оно может применяться на разных уровнях:
До появления встроенного механизма кеширования в Webpack 5 основным
способом ускорения loader-цепочек был cache-loader.
cache-loader использовался для сохранения результатов
работы последующих loader-ов в файловый кеш. Он вставлялся в цепочку
загрузчиков и кешировал результат обработки модуля на основе входного
содержимого и конфигурации.
При первом проходе модуль проходит через цепочку loaders:
source code → loader A → loader B → loader C → output
cache-loader сохраняет результат работы последующих
loaders:
source code → cache-loader → loader A → loader B → loader C → cache write
При повторной сборке:
source code → cache-loader → cache hit → cached output
Типичный пример использования в Webpack 4:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'cache-loader',
options: {
cacheDirectory: path.resolve(__dirname, '.cache-loader')
}
},
{
loader: 'babel-loader'
}
]
}
]
}
};
В этом сценарии cache-loader сохранял результат работы
babel-loader, существенно ускоряя повторные сборки.
Ключ кеша формировался на основе:
Результат сериализовался и сохранялся на диск. При повторной сборке происходило сравнение ключей, и при совпадении возвращался готовый результат без повторного выполнения loader-цепочки.
Со временем подход с cache-loader начал демонстрировать
архитектурные ограничения.
cache-loader кешировал только часть пайплайна —
результаты loader-ов. Он не учитывал весь граф зависимостей Webpack, что
приводило к:
С появлением более продвинутых инструментов кеширования внутри Webpack сам подход стал избыточным:
babel-loader, ts-loader)Сам cache-loader добавлял:
В некоторых сценариях он даже ухудшал производительность при небольших проектах.
Пакет перестал развиваться в пользу встроенных механизмов Webpack 5, что закрепило его статус устаревшего решения.
Webpack 5 представил нативную систему кеширования, интегрированную в компилятор. Она работает на уровне всей сборки, а не отдельных loader-ов.
Основные режимы:
memory — кеш в оперативной памятиfilesystem — персистентный кеш на дискеНаиболее практичный вариант для реальных проектов:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
},
cacheDirectory: path.resolve(__dirname, '.webpack-cache')
}
};
Активирует сохранение кеша на диск. Позволяет ускорять повторные сборки даже после перезапуска процесса.
Определяет директорию хранения кеша. Может быть общей для CI или изолированной для каждого проекта.
Определяет зависимости конфигурации, при изменении которых кеш инвалидируется. Обычно включает:
Webpack 5 кеширует значительно более широкий контекст, чем
cache-loader:
Кеш строится на основе хеширования графа сборки, а не отдельных файлов.
Миграция представляет собой упрощение конфигурации, а не замену функциональности.
Было:
use: [
'cache-loader',
'babel-loader'
]
Стало:
use: [
'babel-loader'
]
Добавляется глобальный кеш:
cache: {
type: 'filesystem'
}
Некоторые loader-ы уже имеют собственные кеши, и их комбинация с filesystem cache может быть избыточной:
babel-loader → cacheDirectoryts-loader → transpileOnly + incremental
buildeslint-loader (устаревший) → cache в eslintПри использовании Webpack 5 часто имеет смысл отключить часть локальных кешей, чтобы избежать дублирования.
babel-loader имеет собственный механизм кеширования:
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
При использовании Webpack filesystem cache этот параметр становится опциональным. В больших проектах возможны два подхода:
ts-loader поддерживает incremental compilation:
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
В связке с Webpack cache это снижает нагрузку на типизацию, оставляя Webpack управление кешем модулей.
Одной из ключевых задач встроенного кеша является корректная инвалидация.
Webpack отслеживает:
require/importОднако внешние зависимости требуют явного указания:
buildDependencies: {
config: [__filename],
tsconfig: [path.resolve(__dirname, 'tsconfig.json')]
}
Без этого возможны ситуации, когда кеш сохраняет устаревшие результаты.
Filesystem cache особенно эффективен в CI/CD:
Типичная практика:
Приводит к двойному кешированию и неожиданным задержкам.
Кеш не инвалидируется при изменении конфигурации.
Комбинация:
создаёт ненужный overhead.
Общий кеш для разных проектов может приводить к конфликтам хешей и некорректным результатам сборки.
Переход от cache-loader к встроенному кешу отражает
общую архитектурную тенденцию Webpack:
Это уменьшает фрагментацию логики и повышает предсказуемость сборки.
В актуальных конфигурациях Webpack 5 базовая схема выглядит так: