Механизм HMR (Hot Module Replacement) в Vite отвечает за обновление модулей без полной перезагрузки страницы. При изменении файла браузер получает уведомление через WebSocket-соединение и применяет обновление мгновенно.
Базовая схема работы выглядит следующим образом:
По умолчанию Vite автоматически определяет адрес HMR-сервера, протокол и порт. Однако в сложных инфраструктурах этого недостаточно:
Для таких случаев используется объект server.hmr.
Пример базовой структуры:
import { defineConfig } from 'vite'
export default defineConfig({
server: {
hmr: {
protocol: 'ws',
host: 'localhost',
port: 24678
}
}
})
При открытии страницы Vite внедряет в клиентский код WebSocket-клиент.
Пример подключения:
ws://localhost:5173/
или:
wss://localhost:5173/
После подключения браузер начинает ожидать сообщения:
{
"type": "update",
"updates": [...]
}
Если соединение разрывается:
Наиболее распространённая ошибка:
WebSocket connection to 'ws://localhost:5173/' failed
Именно для устранения подобных проблем и настраиваются параметры
hmr.
hmr.portПараметр port задаёт порт WebSocket-сервера HMR.
Пример:
export default defineConfig({
server: {
hmr: {
port: 3001
}
}
})
В этом случае HMR будет использовать:
ws://localhost:3001/
а основной dev-сервер может продолжать работать на другом порту.
server.port от hmr.portЭто разные параметры.
server.portПорт HTTP-сервера Vite:
server: {
port: 5173
}
Используется для:
hmr.portПорт WebSocket HMR:
server: {
hmr: {
port: 24678
}
}
Используется исключительно для WebSocket-подключения.
Конфигурация:
export default defineConfig({
server: {
port: 5173,
hmr: {
port: 24678
}
}
})
Результат:
| Назначение | Адрес |
|---|---|
| HTTP сервер | http://localhost:5173 |
| WebSocket HMR | ws://localhost:24678 |
hmr.portОдна из самых частых причин.
Например:
Browser
↓
nginx
↓
Vite
nginx может проксировать HTTP-трафик, но не WebSocket.
В результате:
Пример конфигурации:
server: {
hmr: {
port: 443
}
}
Здесь HMR использует порт HTTPS-прокси.
В Docker контейнере внутренний порт может отличаться от внешнего.
Пример:
Container: 5173
Host: 3000
Без настройки HMR браузер попытается подключиться к:
ws://localhost:5173/
Но этот порт может быть недоступен извне.
Исправление:
server: {
hmr: {
host: 'localhost',
port: 3000
}
}
В WSL2 Vite часто запускается внутри Linux-подсистемы.
Типичная проблема:
WebSocket connection failed
Причина — браузер Windows не может подключиться к внутреннему Linux-адресу.
Решение:
server: {
host: '0.0.0.0',
hmr: {
host: 'localhost',
port: 5173
}
}
При работе через:
адрес WebSocket должен быть доступен извне.
Пример:
server: {
hmr: {
host: 'dev.example.com',
port: 443
}
}
hmr.protocolПараметр protocol определяет WebSocket-протокол.
Возможные значения:
| Значение | Описание |
|---|---|
ws |
обычный WebSocket |
wss |
WebSocket поверх HTTPS |
wsОбычный небезопасный WebSocket.
Пример:
server: {
hmr: {
protocol: 'ws'
}
}
Подключение:
ws://localhost:5173/
Обычно используется:
wssБезопасный WebSocket через TLS.
Пример:
server: {
hmr: {
protocol: 'wss'
}
}
Подключение:
wss://example.com/
wss
обязателен для HTTPSБраузеры запрещают смешанный контент.
Если страница открыта через HTTPS:
https://example.com
то WebSocket через ws:// будет заблокирован.
Ошибка:
Mixed Content:
The page was loaded over HTTPS,
but attempted to connect to the insecure WebSocket endpoint
Поэтому для HTTPS нужен:
hmr: {
protocol: 'wss'
}
import { defineConfig } from 'vite'
export default defineConfig({
server: {
https: true,
hmr: {
protocol: 'wss',
host: 'localhost',
port: 5173
}
}
})
Схема:
Browser
↓ HTTPS
nginx
↓ HTTP
Vite
Конфигурация Vite:
server: {
hmr: {
protocol: 'wss',
host: 'example.com',
port: 443
}
}
nginx должен поддерживать upgrade-запросы WebSocket.
Пример:
location / {
proxy_pass http://localhost:5173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Без этого HMR работать не будет.
clientPortИногда серверный порт и клиентский порт отличаются.
Для этого существует:
hmr.clientPort
server: {
hmr: {
port: 5173,
clientPort: 443
}
}
Здесь:
5173;443.Это особенно полезно при reverse proxy.
hostПараметр определяет адрес HMR-сервера.
Пример:
hmr: {
host: '192.168.0.10'
}
Если устройство открывает Vite с телефона:
http://192.168.0.10:5173
то HMR тоже должен использовать IP:
server: {
host: '0.0.0.0',
hmr: {
host: '192.168.0.10'
}
}
Иначе браузер телефона попытается подключиться к своему собственному localhost.
По умолчанию Vite сам пытается определить:
Обычно этого достаточно для:
Но автоматическое определение часто ломается в:
export default defineConfig({
server: {
host: '0.0.0.0',
port: 5173,
hmr: {
protocol: 'wss',
host: 'dev.example.com',
clientPort: 443
}
}
})
export default defineConfig({
server: {
host: '0.0.0.0',
hmr: {
protocol: 'ws',
host: '192.168.1.15',
port: 5173
}
}
})
export default defineConfig({
server: {
hmr: {
protocol: 'wss',
host: 'example.com',
clientPort: 443
}
}
})
Во вкладке DevTools:
Network → WS
должно отображаться активное WebSocket-соединение.
В консоли браузера можно увидеть:
[vite] connecting...
или:
WebSocket connection to ... failed
Адрес покажет:
Страница:
https://
HMR:
ws://
Результат:
Mixed Content
Например:
localhost
на мобильном устройстве.
Телефон попытается подключиться к своему localhost.
Firewall или Docker могут блокировать порт HMR.
Очень распространённая ошибка.
Без:
proxy_set_header Upgrade $http_upgrade;
WebSocket не будет работать.
import { defineConfig } from 'vite'
export default defineConfig({
server: {
host: '0.0.0.0',
port: 5173,
hmr: {
protocol: 'wss',
host: 'dev.example.com',
port: 5173,
clientPort: 443,
timeout: 30000
}
}
})
hmr| Параметр | Назначение |
|---|---|
protocol |
протокол WebSocket |
host |
адрес подключения |
port |
серверный порт HMR |
clientPort |
порт клиента |
path |
путь WebSocket |
timeout |
timeout соединения |
overlay |
показ overlay ошибок |
overlayУправляет отображением ошибок поверх страницы.
Пример:
hmr: {
overlay: true
}
При ошибках синтаксиса Vite показывает overlay в браузере.
Отключение:
hmr: {
overlay: false
}
timeoutЗадаёт timeout подключения.
Пример:
hmr: {
timeout: 30000
}
Полезно при:
При использовании self-signed сертификатов браузер может блокировать WebSocket.
Симптом:
WebSocket connection failed
Решения:
server: {
hmr: {
protocol: 'ws'
}
}
server: {
https: true,
hmr: {
protocol: 'wss'
}
}
server: {
host: '0.0.0.0',
hmr: {
host: 'localhost',
clientPort: 3000
}
}
server: {
hmr: {
protocol: 'wss',
host: 'example.com',
clientPort: 443
}
}
server: {
host: '0.0.0.0',
hmr: {
host: '192.168.1.10'
}
}