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 заменяет только модуль.

Связанные темы

Ресурсы