Webpack предоставляет механизм наблюдения за изменениями файлов (watch mode), который позволяет автоматически пересобирать бандл при изменении исходного кода. Помимо CLI-режима, этот функционал доступен через программный API, что особенно важно при интеграции Webpack в собственные инструменты, dev-серверы, сборочные пайплайны и системы автоматизации.
Режим наблюдения основан на системе отслеживания файловой системы и
повторном запуске компиляции при изменениях. В Webpack этот механизм
реализован через метод watch, доступный у экземпляра
компилятора.
Ключевая идея:
webpack(config)compiler.watch(...)Перед запуском наблюдения необходимо создать экземпляр компилятора:
const webpack = require('webpack');
const config = require('./webpack.config');
const compiler = webpack(config);
Функция webpack(config) возвращает объект компилятора,
который является центральной точкой управления сборкой.
Метод compiler.watch принимает два основных
параметра:
watchOptions — настройки наблюденияhandler — callback, вызываемый при каждой
компиляцииСигнатура:
compiler.watch(watchOptions, (err, stats) => {});
const webpack = require('webpack');
const config = require('./webpack.config');
const compiler = webpack(config);
compiler.watch({}, (err, stats) => {
if (err) {
console.error(err);
return;
}
console.log(stats.toString({
colors: true,
chunks: false,
modules: false,
}));
});
В этом режиме Webpack будет непрерывно отслеживать изменения и пересобирать проект без необходимости перезапуска процесса.
watchOptions управляют поведением наблюдателя.
Определяет задержку перед запуском сборки после изменений.
compiler.watch({
aggregateTimeout: 300
}, handler);
Значение полезно для уменьшения количества пересборок при серии быстрых изменений (например, при сохранении нескольких файлов подряд).
Включает режим периодического опроса файловой системы.
compiler.watch({
poll: 1000
}, handler);
Значение задаётся в миллисекундах. Этот режим используется, когда файловая система не поддерживает событийное отслеживание (например, в некоторых Docker или сетевых средах).
Позволяет исключить файлы или директории из наблюдения:
compiler.watch({
ignored: /node_modules/
}, handler);
Исключение больших директорий значительно снижает нагрузку на систему наблюдения.
Callback watch получает объект stats,
содержащий информацию о сборке:
Пример форматирования:
stats.toString({
all: false,
errors: true,
warnings: true,
colors: true
});
compiler.watch({}, (err, stats) => {
if (err) {
console.error('Fatal error:', err);
return;
}
if (stats.hasErrors()) {
console.log('Compilation errors occurred');
}
if (stats.hasWarnings()) {
console.log('Compilation warnings occurred');
}
});
Метод watch возвращает объект Watching,
который позволяет управлять процессом:
const watching = compiler.watch({}, handler);
watching.close(() => {
console.log('Watching stopped');
});
После вызова close Webpack прекращает отслеживание
изменений и освобождает ресурсы.
В некоторых сценариях требуется принудительно перезапустить сборку без изменения файлов:
watching.invalidate();
Это приводит к отмене текущей компиляции и запуску новой.
Типичный кейс — интеграция с dev-сервером, где требуется обновление состояния сборки при внешних событиях.
Хотя основной интерфейс — callback, Webpack также предоставляет события через compiler hooks.
compiler.hooks.watchRun.tap('MyPlugin', (comp) => {
console.log('Watch run started');
});
compiler.hooks.watchClose.tap('MyPlugin', () => {
console.log('Watch closed');
});
Это позволяет расширять поведение watch-механизма без модификации основного кода.
Обычный запуск:
compiler.run((err, stats) => {});
Watch-режим:
compiler.watch({}, (err, stats) => {});
Ключевые различия:
run выполняется один разwatch остаётся активным процессомwatch отслеживает зависимости графа модулейrun не имеет механизма повторного запускаWebpack строит граф зависимостей и отслеживает только те файлы, которые участвуют в сборке. Это означает:
При использовании кастомных loaders или plugins важно корректно регистрировать зависимости через:
this.addDependency(filePath);
иначе изменения файлов могут не триггерить rebuild.
При больших проектах режим наблюдения может создавать нагрузку на CPU и файловую систему.
Основные стратегии оптимизации:
ignored: /dist|node_modules/
Webpack cache уменьшает время повторной сборки:
cache: {
type: 'filesystem'
}
stats: 'errors-only'
или
stats: {
modules: false,
chunks: false
}
Хотя Webpack DevServer использует собственный механизм наблюдения, он основан на том же API компилятора. При программной интеграции часто требуется аналогичная логика:
При ошибке сборки watch-режим не останавливается. Он продолжает отслеживать изменения и повторяет попытки компиляции.
compiler.watch({}, (err, stats) => {
if (stats.hasErrors()) {
return;
}
// успешная сборка
});
Такое поведение важно для dev-режима, где исправление ошибки должно автоматически приводить к пересборке без перезапуска процесса.
Программный watch часто используется в следующих архитектурах:
В сложных системах может использоваться несколько компиляторов:
const clientCompiler = webpack(clientConfig);
const serverCompiler = webpack(serverConfig);
clientCompiler.watch({}, handler);
serverCompiler.watch({}, handler);
Каждый компилятор управляет собственным графом зависимостей и независимым процессом сборки.
При нескольких watch-инстансах важно учитывать:
Без этого возможны гонки записи файлов и нестабильные состояния бандла.
Внутри Webpack watch строится на следующих принципах:
Каждая новая итерация использует предыдущий граф, что позволяет избегать полной пересборки проекта.
Корректное завершение процесса важно для освобождения ресурсов:
process.on('SIGINT', () => {
watching.close(() => {
process.exit();
});
});
Без явного закрытия watcher может продолжать удерживать файловые дескрипторы и процессы наблюдения.