Viteの開発サーバーをトンネルするのはうまくいきます — 最初につまずく2つのことを除けば。ページは読み込まれるのにHMRが効かない。あるいはViteがトンネルのホスト名を拒否してページがまったく読み込まれない。どちらも、どこを見ればいいか分かれば設定1行で解決します。
問題1: 「Blocked request. This host is not allowed.」
Vite 5以降はデフォルトでhost-check保護が追加されました。トンネルURLを開いてBlocked request. This host is not allowedと表示されたら、それはこのチェックがあなたの*.portpreview.devホスト名を拒否しています。
vite.config.tsでの修正:
export default defineConfig({
server: {
host: true, // listen on 0.0.0.0
allowedHosts: ['.portpreview.dev'], // accept any subdomain
},
});
先頭のドットでサフィックス一致になります。厳格にしたいなら特定のトンネルホスト名を入れてもよいですが、日々の開発ではサフィックスが便利です — トンネルセッションのURLは入れ替わります。
問題2: HMRが読み込まれた後、静かに死ぬ
HMRはWebSocket上で動きます。Viteがlocalhost:5173で配信し、ブラウザはhttps://abc123.portpreview.devから読み込むと、HMRクライアントはサーバーが伝えたURL — ローカルのもの — に接続しようとします。トンネルはそれを転送しないので、WebSocketは失敗し、HMRは静かに止まります。
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
},
},
});
これでHMRクライアントはwss://abc123.portpreview.dev(ポート443)に接続し、トンネルがアップグレードを転送して、編集が期待どおり反映されます。静的リロードだけで十分でトンネル越しのHMRが不要なら、これは飛ばせます — ただしcmd-Rを多用することになります。
そもそもなぜViteをトンネルしたいのか
本当の理由は3つ:
- モバイルテスト。 URLをスマホで開けば、HMR付きで同じビルドが見えます。画面共有やデバイス別エミュレータより優れています。完全なパターンはトンネルでのモバイルテストを参照。
- 進行中の作業の共有。 デザイナーやPMにリンクを送れば、あなたのブランチをライブで見られます。デプロイ手順は不要です。
- HTTPSが必要なOAuthやWebhookのフロー。 Stripe(リダイレクトのみ)やAuth0などと話すVite配信のフロントエンド。選び方はmkcert対トンネルで扱っています。
SvelteKit、Astro、SolidStartはすべてViteを使う
上記の設定は、開発サーバーとしてViteを出荷するあらゆるフレームワークに当てはまります。SvelteKitのvite.config.jsも同じ形です。Astroはviteサブオブジェクトを持つ独自のastro.config.mjsがあります — そこに同じserverオプションを置きます。SolidStart、Nuxt 3(Vite経由)、Qwik Cityも同じパターンです。
本番ビルドは別の話
上記はすべて開発サーバーの設定です。vite previewを実行したりビルド済みバンドルを配信したりするときは、HMRもhost-checkミドルウェアもないため、何も関係ありません。その時点でトンネルは静的ファイルを転送しているだけです。
小さなこといくつか
- 厳格なhost CORS。 フロントエンドが別オリジン(別のlocalhostポート、または別のAPIトンネル)のAPIを叩くなら、API側でCORSを設定します。Viteは
server.proxyで指示しない限りデフォルトではプロキシしません。 - WebSocketを多用するアプリ。 Vite HMRはWebSocketが1つです。アプリがゲーム状態、チャット、ライブデータ用に別のWebSocketを使うなら、それは別物で、クライアントコードでもトンネルURLを使うように設定する必要があります。
- env ファイルのトンネルURL。 フロントエンドが自分の公開アドレスを知る必要があるとき、アクティブなトンネルURLを
.env.localにVITE_PUBLIC_URLとして入れます。import.meta.env.VITE_PUBLIC_URLでクライアントから読みます。
手順
server.host、allowedHosts、hmrブロックをVite設定に追加します。- 開発サーバーを再起動します。
npx portpreview 5173(またはViteが使うポート)を実行します。- ブラウザかスマホでHTTPS URLを開きます。
- コンポーネントを編集します。HMRがフルリロードなしでページを更新することを確認します。
HMRが更新しないなら、ブラウザのコンソールを開きましょう — ViteはWebSocket接続の試行をログに出し、試したURLが見えます。それでhmr.clientPort/protocolの変更が効いたか分かります。
WebSocketアップグレードをデフォルトで保持するトンネルのために、PortPreviewのウェイトリストに登録してください。