В разработке приложения на JavaScript есть одна особенность: каждый раз при сохранении изменений кода для обновления пользовательского интерфейса приходится перезагружать браузер.

Для отслеживания изменений в файлах проекта инструменты разработчика, такие как Webpack, запускаются даже в режиме просмотра. Обнаружив изменение, Webpack выполняет повторную сборку приложения, а браузер автоматически перезагружается.

Разработчикам это быстро надоело, и они задумались: а нет ли какого-нибудь способа сохранять и отображать изменения в браузере без перезагрузки? Ведь перезагрузка чревата потерей любого процесса, создаваемого в пользовательском интерфейсе.

  • Исчезает любое модальное или диалоговое окно, с которым ведется работа. И приходится возвращаться назад и повторять все сначала, чтобы окна появились снова.
  • Происходит сброс состояния приложения. Если при этом используются библиотеки типа React или Vue, то для изменения или сохранения состояния в локальном хранилище процесс приходится повторять.
  • Сохранение состояния в локальном хранилище сопряжено с написанием дополнительного кода. Каждый раз приходится добавлять и удалять код, и это очень неудобно (если, конечно, вы не сохраняете состояние в продакшене).
  • Даже небольшое изменение в коде CSS приводит к перезагрузке браузера.

Для решения этих проблем был создан механизм горячей замены модулей, который сегодня способствует ускорению фронтенд-разработки.

Как работает механизм горячей замены модулей

Механизм горячей замены модулей позволяет заменять, добавлять или удалять модули JavaScript во время работы приложения и делать все это без перезагрузки браузера. В Webpack это стало возможным благодаря созданию сервера горячей замены модулей внутри Webpack Development Server (webpack-dev-server), который взаимодействует со средой выполнения горячей замены модулей в браузере через websocket.

Схема работы механизма горячей замены модулей

Процесс замены модулей выглядит следующим образом.

  • При первой сборке приложения Webpack генерирует файл манифеста, который содержит хеш компиляции и список всех модулей. Webpack добавляет среду выполнения горячей замены модулей в сгенерированный файл bundle.js.
  • Изменения в файле, которые обнаруживает Webpack, сохраняются.
  • Компилятор Webpack выполняет сборку приложения с учетом изменений, создавая новый файл манифеста и сравнивая его со старым. Этот процесс называется hot update («Горячее обновление»).
  • Hot update отправляется на сервер горячей замены модулей, откуда обновления переправляются в среду выполнения горячей замены модулей.
  • В среде выполнения горячей замены модулей hot update распаковываетсяи для обработки изменений используется соответствующий загрузчик. Если изменения касаются CSS, вызывается CSS loader или Style loader. Если же изменения происходят в коде JavaScript, вызывается обычно Babel loader.

Применение механизма горячей замены модулей избавляет от необходимости обновлять браузер для загрузки нового бандла. Среда выполнения горячей замены модулей принимает входящие запросы от сервера горячей замены модулей, который содержит файл манифеста с фрагментами кода, идущий на замену уже имеющегося в браузере.

Если задействуется механизм горячей замены модулей, то при сохранении изменений кода во время работы приложения файл горячего обновления hot update отправляется с сервера горячей замены модулей во вкладку Network:

Файлы горячего обновления hot update во вкладке Network

Если горячему обновлению hot update не удается заменить код в браузере, среда выполнения горячей замены модулей сообщает об этом серверу webpack-dev-server. После чего webpack-dev-server обновляет браузер для загрузки нового файла bundle.js. Отменить такое поведение просто: достаточно добавить hotOnly: true в конфигурацию Webpack.

Как активировать механизм горячей замены модулей

Чтобы задействовать механизм горячей замены модулей в проекте, надо указать приложению, как обрабатывать горячие обновления hot updates. Это делается с помощью API module.hot, который предоставляется в Webpack.

Сначала в конфигурационный файл Webpack добавляется hot: true:

// webpack.config.js

module.exports = {
  entry: {
     app: './src/index.js',
  },
  devtool: 'inline-source-map',
  devServer: {
    hot: true,
    // ... другая конфигурация пропущена
  },
  plugins: [
    // Задействуется плагин
    new webpack.HotModuleReplacementPlugin(),
  ],
}

После этого необходимо с помощью API module.hot обработать входящий запрос горячей замены модулей. Вот пример реализации в проекте на vanilla JS:

// index.js

import component from "./component";

document.body.appendChild(component);

// Проверяется, активирован ли интерфейс горячей замены модулей
if (module.hot) {
  // Принимается горячее обновление hot update
  module.hot.accept();
}

Как только горячее обновление принято, среда выполнения горячей замены модулей и загрузчики переходят к обработке обновления.

Надо сказать, что сделать реализацию горячей замены модулей для сложных приложений бывает не так просто. Связано это с нежелательными побочными эффектами, например обработчик событий, привязанный к старой функции. Трудности здесь возникают в основном из-за использования библиотеки React или Vue. Кроме того, необходимо подключать механизм горячей замены модулей только в режиме разработки.

Прежде чем пытаться самостоятельно реализовывать механизм горячей замены модулей, поищите уже имеющиеся решения для своего проекта. Ведь горячая замена модулей интегрирована во многие популярные генераторы приложений JavaScript.

React Fast Refresh (реализация горячей перезагрузки для React) есть в Create React App и в Next.js. А в Vue CLI 3 механизм горячей замены модулей реализован с помощью vue-loader. В Svelte и Angular тоже имеются собственные интеграции горячей замены модулей, так что писать реализации с нуля здесь не потребуется.

Заключение

Горячая замена модулей  —  это механизм, дающий возможность видеть изменения кода в браузере без его перезагрузки. А еще он позволяет сохранить состояние клиентского приложения.

Но сделать реализацию горячей замены модулей бывает непросто из-за возможного возникновения побочных эффектов. К счастью, горячая замена модулей уже интегрирована во многие генераторы приложений JavaScript, так что самостоятельно делать реализацию этого механизма не придется.

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Nathan Sebhastian: Webpack’s Hot Module Replacement Feature Explained

Предыдущая статьяМеньше образы Docker => быстрее CI-конвейер
Следующая статьяЗачем изучать программирование?
6 способов освоить кодинг дома