module.hot является частью механизма Hot Module Replacement (HMR) в Webpack и предоставляет API для управления жизненным циклом модулей во время их горячей замены без полной перезагрузки страницы. В рантайме Webpack каждый модуль может получать доступ к объекту module.hot, который существует только при включённом HMR. Через него определяется, как именно модуль реагирует на обновления зависимостей, как очищает ресурсы и как принимает новые версии кода.
Hot Module Replacement относится к категории Hot Module Replacement и позволяет обновлять отдельные части приложения, сохраняя состояние остальной системы. Поведение определяется не только конфигурацией devServer, но и тем, как каждый модуль реализует обработчики через module.hot.
Объект module.hot появляется только в режиме разработки при включённой опции hot. В production-сборках он отсутствует, и любые проверки должны учитывать это:
if (module.hot) {
// HMR логика
}
Каждый модуль рассматривается как узел графа зависимостей. Когда изменяется исходный файл, Webpack строит обновлённый модуль и анализирует цепочку зависимостей, чтобы определить границы обновления. Если модуль объявил обработчик accept, он становится точкой остановки распространения обновления.
accept является основным механизмом указания, что модуль способен принять обновление без полной перезагрузки.
module.hot.accept();
В этом варианте модуль принимает обновления самого себя. Webpack заменяет код модуля, но не перезапускает приложение.
Наиболее распространённый сценарий — отслеживание зависимостей:
module.hot.accept('./math.js', function () {
const updatedMath = require('./math.js');
console.log(updatedMath.sum(2, 2));
});
Здесь происходит следующее:
module.hot.accept(['./a.js', './b.js'], () => {
const a = require('./a.js');
const b = require('./b.js');
});
Такой подход применяется при координированных обновлениях модулей, связанных общей логикой.
Если модуль не вызывает accept для изменённой зависимости, обновление поднимается вверх по дереву. Webpack ищет ближайший модуль, который способен принять обновление.
Пример поведения:
A → B → C
Если изменился C:
Если ни один модуль не принимает обновление, происходит полный reload страницы.
decline используется для явного запрета принятия обновлений от зависимостей. Это инструмент управления границами HMR.
module.hot.decline('./api.js');
Это означает, что любые изменения в ‘./api.js’ не должны приводить к частичному обновлению этого модуля.
module.hot.decline();
В этом случае модуль полностью отказывается от HMR и заставляет систему выполнять полный reload при любых изменениях в его зависимости.
decline устанавливает жесткую границу:
decline используется в случаях, когда:
dispose применяется для очистки ресурсов перед заменой модуля. Это ключевой механизм предотвращения утечек памяти и дублирования побочных эффектов.
module.hot.dispose(function (data) {
clearInterval(timer);
removeEventListener('resize', handler);
});
dispose вызывается:
Одной из особенностей dispose является возможность передачи состояния между версиями модуля:
module.hot.dispose(function (data) {
data.counter = counter;
});
Затем в новом модуле:
if (module.hot.data) {
counter = module.hot.data.counter;
}
Таким образом:
let interval = setInterval(() => {}, 1000);
module.hot.dispose(() => {
clearInterval(interval);
});
function handler() {}
window.addEventListener('scroll', handler);
module.hot.dispose(() => {
window.removeEventListener('scroll', handler);
});
const subscription = store.subscribe(listener);
module.hot.dispose(() => {
subscription.unsubscribe();
});
accept и dispose часто используются совместно:
function render() {
console.log('render');
}
render();
if (module.hot) {
module.hot.accept('./view.js', () => {
render();
});
module.hot.dispose(() => {
console.log('cleanup');
});
}
Порядок выполнения при обновлении:
Если в цепочке модулей:
Webpack может:
decline в таких случаях предотвращает частичное обновление и переводит систему в режим полной перезагрузки.
module.hot применяется только к:
Не поддерживаются:
module.hot формирует слой управления над стандартным графом зависимостей:
Эти три механизма позволяют Webpack выполнять инкрементальную замену модулей без разрушения всего runtime, сохраняя консистентность приложения и минимизируя стоимость пересборки пользовательского интерфейса.