HMR: Hot Module Replacement
HMR (Hot Module Replacement) — технология, позволяющая заменять модули в работающем приложении без полной перезагрузки страницы, сохраняя текущее состояние UI.
Зачем нужно
Без HMR каждое изменение кода требует полной перезагрузки страницы и возврата к начальному состоянию приложения. С HMR изменённый модуль подменяется в runtime: React-компонент обновляется, стили применяются — а состояние (введённый текст, позиция скролла, открытые модалки) сохраняется. Это радикально ускоряет итерации при разработке.
Где используется
- Vite (встроен, работает из коробки с React Fast Refresh)
- Webpack с
webpack-dev-serverиwebpack.HotModuleReplacementPlugin - Create React App — использует webpack HMR под капотом
- Next.js — Fast Refresh для React компонентов
Как работает HMR
1. Разработчик сохраняет файл
2. Webpack/Vite обнаруживает изменение
3. Пересобирает только изменённый модуль и его зависимости
4. Отправляет патч браузеру через WebSocket
5. Runtime заменяет старый модуль новым
6. Компоненты обновляются без полного обновления страницы
React Fast Refresh (Vite + React)
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react'; // включает Fast Refresh
export default defineConfig({
plugins: [react],
server: {
port: 3000,
// HMR работает автоматически
},
});
Webpack HMR — ручная настройка
// webpack.config.js
const webpack = require('webpack');
module.exports = {
mode: 'development',
devServer: {
hot: true, // включить HMR
port: 3000,
},
plugins: [
new webpack.HotModuleReplacementPlugin,
],
};
HMR API (низкоуровневый)
// Принять обновление для текущего модуля
if (module.hot) {
module.hot.accept('./someModule', () => {
// Вызывается при обновлении someModule
const newModule = require('./someModule');
// Обновить использование модуля
});
module.hot.dispose((data) => {
// Cleanup перед заменой модуля
// data — объект для передачи состояния новому модулю
data.state = currentState;
});
}
Ограничения React Fast Refresh
// РАБОТАЕТ — экспортирует только компоненты
export default function Button() { ... }
export function Input() { ... }
// НЕ РАБОТАЕТ с Fast Refresh — смешанный экспорт
export default function Button() { ... }
export const CONSTANT = 42; // non-component экспорт → full reload
Частые ошибки
- HMR не работает с side effects на уровне модуля — код вне компонентов (подписки, таймеры инициализации) не сбрасывается при HMR; нужна очистка через
module.hot.dispose. - Состояние не сохраняется при изменении структуры хука — если меняется порядок вызова хуков, React вынужден размонтировать компонент.
- Путают HMR с Live Reload — Live Reload перезагружает всю страницу, HMR заменяет только модуль.