В основе Hot Module Replacement лежит граф модулей и система распространения обновлений от изменённых модулей вверх по цепочке зависимостей. При каждом изменении исходного кода webpack формирует новый chunk hash, сравнивает сборки и пытается применить различия к уже загруженному в браузере runtime.
Процесс обновления включает несколько этапов:
Полная перезагрузка страницы становится крайним вариантом, когда хотя бы один из этапов нарушает целостность цепочки применения обновлений.
Если сборка завершается с ошибкой, HMR вообще не инициируется. В этом случае dev server переходит в режим ожидания корректной сборки, после чего может инициировать reload.
Типичные причины:
При этом webpack dev server различает два состояния:
Даже при успешной сборке обновление может быть отменено, если во время выполнения hot runtime возникает ошибка:
hot.accept обработчикеКогда runtime фиксирует необрабатываемую ошибку, обновление помечается как «invalidated», и система часто инициирует full reload для восстановления консистентного состояния.
Одно из ключевых ограничений HMR — необходимость явного или косвенного принятия обновления.
Если модуль не определяет:
module.hot.accept()то обновление считается «unaccepted».
В этом случае webpack runtime:
Особенно часто это происходит в следующих ситуациях:
HMR работает через propagation graph: изменение поднимается от изменённого модуля к родителям, пока не встретит accept boundary.
Сбой возникает, если:
В этом случае runtime фиксирует:
Aborted because module is not acceptedи переходит к полной перезагрузке.
При изменении интерфейса модуля (экспортов, типов, побочных эффектов) HMR может не суметь корректно применить патч.
Типичные случаи:
Webpack не выполняет глубокий семантический анализ, поэтому несовместимость часто проявляется только в runtime и приводит к fallback.
Если включён liveReload, dev server использует HMR как
предпочтительный механизм, но при его невозможности инициирует reload
страницы.
Сценарии:
Параметр hotOnly (или devServer.hot = true
без liveReload) изменяет поведение:
В классической конфигурации без hotOnly fallback происходит автоматически.
HMR зависит от канала связи между браузером и dev server:
При восстановлении соединения webpack сравнивает текущий hash и может инициировать full reload, если состояние runtime неизвестно.
При частичном обновлении может возникнуть ситуация, когда:
Это приводит к состоянию «mixed graph», которое webpack считает небезопасным для hot apply.
Результат:
При использовании code splitting возможны проблемы:
Если общий chunk затрагивает множество entry points, HMR часто не может гарантировать корректное применение изменений.
При оптимизациях сборки:
В результате HMR runtime не находит обработчик обновления.
Если несколько модулей объявляют конкурирующие accept handlers:
Webpack выбирает conservative strategy — при сомнении выполняется full reload.
Хотя CSS HMR обычно стабильнее JS, ошибки возникают при:
В таких случаях возможны:
Даже если обновление применилось успешно, следующий сценарий критичен:
Webpack runtime не выполняет rollback изменений, поэтому:
HMR опирается на структуру:
Деградация происходит, если:
При невозможности построить путь принятия обновления применяется стратегия fallback.
Внутренние причины отказа hot update:
Cannot apply update. Need full reload.Module not acceptedDispose handler failedUpdate propagation failedAborted due to error in self-accepted moduleКаждая из них указывает на невозможность безопасной инъекции изменений в существующий runtime без перезапуска страницы.
С точки зрения архитектуры модулей ключевым фактором является наличие устойчивых hot boundaries:
module.hot.accept на уровне компонентовПри нарушении этих принципов вероятность fallback к full reload резко возрастает, особенно в приложениях с большим числом взаимозависимостей и динамической загрузкой чанков