Система кэширования в Webpack предназначена для ускорения повторных сборок. Во время первой компиляции Webpack анализирует граф зависимостей, преобразует модули, выполняет работу лоадеров и плагинов, после чего сохраняет промежуточные результаты. При следующем запуске часть вычислений может быть восстановлена из кэша, что значительно уменьшает время сборки.
Ключевую роль в файловом кэшировании играют параметры:
cacheDirectorycacheLocationОба параметра связаны с расположением файлов кэша на диске, однако используются в разных механизмах и версиях экосистемы Webpack.
В Webpack 4 и ранних версиях полноценного встроенного persistent cache не существовало. Основной механизм ускорения сборки обеспечивали:
cache-loaderbabel-loadernode_modules/.cacheИменно в этот период широкое распространение получил параметр
cacheDirectory.
Пример:
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
В этом случае babel-loader создавал каталог кэша и
сохранял туда результаты трансформации Babel.
Webpack 5 внедрил полноценную файловую систему кэширования:
module.exports = {
cache: {
type: 'filesystem'
}
};
Теперь Webpack самостоятельно сохраняет:
В рамках этой системы появился параметр
cacheLocation.
cacheDirectorycacheDirectorycacheDirectory чаще всего относится не к самому Webpack,
а к отдельным инструментам:
babel-loadereslint-loaderpostcss-loaderterser-webpack-pluginНаиболее распространённый пример — babel-loader.
cacheDirectorymodule.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
]
}
};
При значении true Babel создаёт директорию
автоматически.
Обычно используется:
node_modules/.cache/babel-loader
Вместо true можно указать путь:
options: {
cacheDirectory: path.resolve(__dirname, '.babel-cache')
}
Теперь кэш будет храниться в:
.babel-cache
cacheDirectorybabel-loader кэширует:
Это избавляет Babel от повторной обработки неизменённых файлов.
Без кэша:
Initial build: 18s
Rebuild: 16s
С cacheDirectory:
Initial build: 19s
Rebuild: 2s
Первый запуск может быть немного медленнее из-за записи кэша, но последующие сборки значительно ускоряются.
cacheDirectoryLoader вычисляет специальный hash на основе:
Если hash совпадает, результат берётся из кэша.
Кэш автоматически пересоздаётся при изменении:
{
"presets": ["@babel/preset-env"]
}
Например, добавление нового preset:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
приведёт к полной перестройке кэша.
cacheDirectorycacheDirectory не ускоряет:
Он ускоряет только работу конкретного инструмента.
Большие проекты могут создавать гигабайты временных файлов:
node_modules/.cache/
Особенно при:
Если узким местом является:
то cacheDirectory почти не поможет.
cacheLocationcacheLocation относится уже к встроенному filesystem
cache Webpack 5.
Пример:
module.exports = {
cache: {
type: 'filesystem',
cacheLocation: path.resolve(__dirname, '.webpack-cache')
}
};
Webpack будет сохранять persistent cache в:
.webpack-cache
module.exports = {
cache: {
type: 'filesystem'
}
};
По умолчанию Webpack создаёт каталог:
node_modules/.cache/webpack
cacheLocationconst path = require('path');
module.exports = {
cache: {
type: 'filesystem',
cacheLocation: path.resolve(
__dirname,
'.cache/webpack'
)
}
};
В отличие от cacheDirectory, persistent cache Webpack
значительно шире.
Кэшируются:
Это полноценное состояние сборки.
После сборки можно увидеть:
.cache/
└── webpack/
├── default-development/
├── default-production/
└── index.pack
Webpack создаёт отдельные сегменты кэша для:
cacheLocationWebpack сериализует внутренние структуры:
После этого данные записываются в бинарные pack-файлы.
При следующем запуске Webpack:
Если файлы не изменились, пересборка не требуется.
cacheLocation и
nameWebpack может использовать несколько независимых кэшей.
Пример:
cache: {
type: 'filesystem',
name: 'client-cache',
cacheLocation: path.resolve(
__dirname,
'.cache/client'
)
}
Для server bundle:
cache: {
type: 'filesystem',
name: 'server-cache',
cacheLocation: path.resolve(
__dirname,
'.cache/server'
)
}
Это особенно важно при:
node_modules/.cache/
Преимущества:
node_modulesНедостатки:
node_modules уничтожает кэш.cacheproject/
├── .cache/
│ └── webpack/
├── src/
└── package.json
Преимущества:
node_modulesLinux:
cacheLocation: '/tmp/webpack-cache'
macOS:
cacheLocation: '/private/tmp/webpack-cache'
Преимущества:
Недостатки:
В CI каждый pipeline часто стартует с пустого окружения.
Без сохранения cache:
Build #1: 9m
Build #2: 9m
Build #3: 9m
Например:
.cache/webpack
можно сохранять между pipeline.
GitHub Actions:
- uses: actions/cache@v3
with:
path: .cache/webpack
key: webpack-cache
Webpack умеет автоматически инвалидировать кэш при изменении конфигурации.
Пример:
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
}
Если меняется webpack.config.js, кэш сбрасывается.
Webpack 5 использует snapshot-механизм.
Snapshot содержит:
Это позволяет быстро понимать:
Filesystem cache сильно зависит от скорости диска.
Проблемы:
Преимущества:
На NVMe разница особенно заметна в крупных monorepo.
Крупные проекты могут создавать:
5-20 GB cache
Причины:
Огромное количество мелких файлов может ухудшать производительность:
rm -rf node_modules/.cache
rm -rf node_modules/.cache/webpack
rm -rf node_modules/.cache/babel-loader
Если постоянно меняются:
то invalidation может происходить почти на каждой сборке.
Некоторые loader’ы:
Это делает кэш малоэффективным.
cacheDirectory и cacheLocationОба механизма могут использоваться одновременно.
Пример:
module.exports = {
cache: {
type: 'filesystem',
cacheLocation: path.resolve(
__dirname,
'.cache/webpack'
)
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
cacheDirectory: path.resolve(
__dirname,
'.cache/babel'
)
}
}
]
}
};
Кэширует:
Кэширует:
Типичный сценарий:
| Конфигурация | Rebuild |
|---|---|
| Без cache | 20s |
| Только Babel cache | 8s |
| Только filesystem cache | 4s |
| Оба cache | 1.5s |
Современный стандарт:
cache: {
type: 'filesystem'
}
.gitignore:
.cache
node_modules/.cache
cache: {
type: 'filesystem',
name: process.env.NODE_ENV
}
.cache/client
.cache/server
Нежелательно:
cacheLocation: `/tmp/${Date.now()}`
Это полностью ломает повторное использование кэша.
Плохой вариант:
RUN npm install
RUN npm run build
При изменении любого файла весь слой инвалидируется.
Опасный вариант:
cacheLocation: '/tmp/webpack-cache'
для нескольких независимых проектов.
Возможны:
Например:
Filesystem cache может работать медленнее, чем без кэша.
cacheDirectory и cacheLocation| Параметр | cacheDirectory |
cacheLocation |
|---|---|---|
| Относится к | loader | Webpack |
| Основная задача | кэш трансформаций | persistent build cache |
| Появился | до Webpack 5 | Webpack 5 |
| Масштаб кэша | локальный | глобальный |
| Тип данных | transpilation results | build graph |
| Чаще всего используется | Babel | Webpack filesystem cache |
| Влияет на rebuild | частично | значительно |
| Ускоряет resolver | нет | да |
| Ускоряет chunk graph | нет | да |
| Поддерживает snapshots | нет | да |