Wszystkie artykuły
ViteHMRlocal developmentlocalhost tunneling

Vite + tunel: HMR, które naprawdę działa

Tunelowanie serwera deweloperskiego Vite działa dobrze — poza dwiema rzeczami, które podłożą ci nogę za pierwszym razem. Strona się ładuje, ale HMR nie. Albo strona w ogóle się nie ładuje, bo Vite odrzuca nazwę hosta tunelu. Oba to jednolinijkowe poprawki konfiguracji, gdy wiesz, gdzie patrzeć.

Problem 1: „Blocked request. This host is not allowed."

Vite 5+ dodał domyślnie ochronę host-check. Jeśli otworzysz adres tunelu i zobaczysz Blocked request. This host is not allowed, to ta kontrola odrzuca twoją nazwę hosta *.portpreview.dev.

Poprawka w vite.config.ts:

export default defineConfig({
  server: {
    host: true,                            // listen on 0.0.0.0
    allowedHosts: ['.portpreview.dev'],   // accept any subdomain
  },
});

Wiodąca kropka czyni z tego dopasowanie po sufiksie. Możesz wpisać tam konkretną nazwę hosta tunelu, jeśli wolisz być rygorystyczny, ale na co dzień sufiks jest wygodny — adresy sesji tunelu się zmieniają.

Problem 2: HMR się ładuje, potem cicho umiera

HMR działa po WebSocket. Gdy Vite serwuje pod localhost:5173, ale przeglądarka ładuje z https://abc123.portpreview.dev, klient HMR próbuje połączyć się z adresem, który podał mu serwer — lokalnym. Tunel tego nie przekazuje, więc WebSocket zawodzi i HMR cicho się zatrzymuje.

Popraw konfigurację HMR:

export default defineConfig({
  server: {
    host: true,
    allowedHosts: ['.portpreview.dev'],
    hmr: {
      clientPort: 443,            // browser connects on 443 (HTTPS)
      protocol: 'wss',            // secure WebSocket through the tunnel
    },
  },
});

Teraz klient HMR łączy się z wss://abc123.portpreview.dev (port 443), tunel przekazuje upgrade, a edycje propagują się zgodnie z oczekiwaniami. Jeśli potrzebujesz tylko statycznego przeładowania i nie zależy ci na HMR przez tunel, możesz to pominąć — ale będziesz dużo używać cmd-R.

Dlaczego w ogóle tunelować Vite

Trzy realne powody:

  • Testy mobilne. Otwórz adres na telefonie, zobacz ten sam build z HMR. Lepsze niż współdzielenie ekranu czy emulatory na urządzenie. Zobacz testy mobilne z tunelem, by poznać pełny wzorzec.
  • Udostępnianie pracy w toku. Wyślij link projektantowi lub PM-owi, zobaczą twoją gałąź na żywo. Bez kroku wdrożenia.
  • Przepływy OAuth i webhooków wymagające HTTPS. Frontendy serwowane przez Vite, które rozmawiają ze Stripe (tylko redirect), Auth0 itp. mkcert vs. tunel omawia wybór.

SvelteKit, Astro, SolidStart używają Vite

Powyższe konfiguracje dotyczą każdego frameworka, który dostarcza Vite jako serwer deweloperski. vite.config.js SvelteKita ma ten sam kształt. Astro ma własny astro.config.mjs z podobiektem vite — wstaw tam te same opcje server. SolidStart, Nuxt 3 (przez Vite) i Qwik City: ten sam wzorzec.

Buildy produkcyjne to inna historia

Wszystko powyżej to konfiguracja serwera deweloperskiego. Gdy uruchamiasz vite preview lub serwujesz zbudowany bundle, nic z tego nie ma znaczenia, bo nie ma HMR ani middleware host-check. Tunel przekazuje wtedy tylko statyczne pliki.

Kilka drobiazgów

  • Rygorystyczny host-CORS. Jeśli frontend uderza do API na innym origin (inny port localhost lub osobny tunel API), ustaw CORS po stronie API. Vite domyślnie nie proxuje, dopóki nie powiesz mu tego przez server.proxy.
  • Aplikacje mocno korzystające z WebSocket. HMR Vite to jeden WebSocket. Jeśli twoja aplikacja używa innego WebSocket do stanu gry, czatu lub danych na żywo, jest on osobny i też musi być skonfigurowany w kodzie klienta na adres tunelu.
  • Adres tunelu w plikach env. Aktywny adres tunelu umieszczamy w .env.local jako VITE_PUBLIC_URL, gdy frontend musi znać własny publiczny adres. import.meta.env.VITE_PUBLIC_URL odczytuje go w kliencie.

Krok po kroku

  1. Dodaj blok server.host, allowedHosts i hmr do konfiguracji Vite.
  2. Zrestartuj serwer deweloperski.
  3. Wykonaj npx portpreview 5173 (lub port, którego używa Vite).
  4. Otwórz adres HTTPS w przeglądarce lub na telefonie.
  5. Zedytuj komponent. Potwierdź, że HMR aktualizuje stronę bez pełnego przeładowania.

Jeśli HMR nie aktualizuje, otwórz konsolę przeglądarki — Vite loguje próbę połączenia WebSocket i zobaczysz adres, którego próbował. To mówi, czy zmiana hmr.clientPort/protocol zadziałała.

Dołącz do listy oczekujących PortPreview, by mieć tunele zachowujące upgrade'y WebSocket domyślnie.

Najczęściej zadawane pytania

Dlaczego Vite blokuje mój adres tunelu z „host is not allowed"?
Vite 5+ dodał host-check, który domyślnie odrzuca nieznane nazwy hostów. Dodaj allowedHosts: ['.portpreview.dev'] (lub swoją domenę tunelu) do konfiguracji server, aby akceptować żądania tunelu.
Jak sprawić, by HMR Vite działało przez tunel?
Ustaw hmr.clientPort: 443 i hmr.protocol: 'wss' w vite.config.ts. To każe klientowi HMR łączyć się przez HTTPS/WSS tunelu zamiast próbować sięgać localhost bezpośrednio, co zawodzi spoza twojej maszyny.
Czy to działa dla SvelteKit, Astro i Nuxt?
Tak. Każdy framework używający Vite jako serwera deweloperskiego przyjmuje tę samą konfigurację server.host, allowedHosts i hmr. Astro zagnieżdża ją pod vite w astro.config.mjs; pozostałe wstawiają ją w swój zwykły plik konfiguracji Vite.