Hot Module Replacement (HMR) в Vite основан на нативной поддержке ES-модулей и WebSocket-соединении между dev-сервером и браузером. В контексте CSS это означает возможность обновления стилей без полной перезагрузки страницы и без потери состояния приложения.
CSS рассматривается Vite как особый тип модуля, который не требует
JavaScript-обёртки для применения изменений. При изменении файла стилей
Vite генерирует обновлённый модуль и отправляет сигнал клиенту, после
чего браузер заменяет соответствующий <style> или
<link> ресурс.
Ключевая особенность заключается в том, что CSS HMR работает на уровне инвалидации модулей, а не полной перезагрузки графа приложения.
При импорте CSS в Jav * aScript:
import './styles.css'
Vite выполняет несколько шагов:
<style> в документКаждый CSS-файл становится наблюдаемым узлом в модульном графе Vite. Это позволяет точно определять, какие части приложения должны обновиться при изменении файла.
При изменении CSS-файла Vite выполняет следующие действия:
В отличие от JavaScript HMR, CSS не требует выполнения accept-логики. Обновление происходит автоматически.
CSS часто импортируется через цепочку модулей:
import './base.css'
import './layout.css'
import './theme.css'
При изменении одного файла Vite:
Это обеспечивает минимальный радиус обновления и стабильное состояние интерфейса.
CSS по своей природе зависит от каскада и специфичности. HMR в Vite учитывает это косвенно:
<style> происходит с учётом
исходной позицииЕсли порядок импорта меняется, Vite может пересоздать часть style-инъекций, чтобы сохранить корректный cascade.
CSS Modules в Vite используют суффикс .module.css:
import styles from './button.module.css'
В этом случае CSS обрабатывается иначе:
При изменении файла .module.css происходит двойное
обновление:
Vite отправляет HMR-событие, которое приводит к:
stylesПример:
import styles from './button.module.css'
button.className = styles.primary
После изменения CSS Module объект styles.primary может
получить новый хэш, и Vite гарантирует, что импорт обновится без
перезагрузки страницы.
HMR в CSS Modules имеет важное ограничение: имена классов могут изменяться при каждом обновлении, если изменяется содержимое файла.
Это приводит к следующим особенностям:
styles.* должны оставаться актуальнымиCSS Modules тесно связаны с JS HMR, поскольку экспортируются как объект:
export default {
button: "button_hash_123"
}
При изменении CSS:
Таким образом CSS Modules фактически являются гибридным типом модуля.
Vite строит граф зависимостей, где CSS и CSS Modules могут иметь следующие связи:
@import)При изменении одного узла:
Особенно важно поведение при @import:
@import './reset.css';
Vite превращает такие импорты в часть графа модулей, а не оставляет их на уровне CSS-движка браузера.
@importПри использовании @import:
Однако порядок применения может изменяться, если изменяется структура импорта.
Vite управляет стилями через динамическую вставку:
<style> тег для каждого CSS-модуляДля CSS Modules структура более сложная:
Несмотря на высокую скорость обновления, существуют ограничения:
@import могут приводить к
перестройке нескольких модулейCSS Modules уменьшают часть этих проблем за счёт локализации классов, но не устраняют их полностью.
Vite оптимизирует CSS HMR следующим образом:
<style>Это обеспечивает обновление стилей практически без задержек даже в больших проектах.
Поведение CSS HMR может отличаться в зависимости от используемого фреймворка:
Однако сам механизм Vite остаётся одинаковым — обновление модулей через HMR runtime.
Некоторые ситуации требуют особого поведения:
В таких случаях HMR работает корректно на уровне файлов, но логика применения классов зависит от архитектуры приложения.
Vite рассматривает CSS как полноценный модуль первого класса, а CSS Modules как расширенный тип модуля с дополнительным JS-слоем. Это позволяет объединить:
Такой подход делает CSS HMR не отдельной подсистемой, а частью общего графа модулей приложения.