所有文章
ViteHMRlocal developmentlocalhost tunneling

Vite + 隧道:真正能用的 HMR

把 Vite 开发服务器穿隧道用起来很顺——除了两件第一次会绊住你的事。页面加载了但 HMR 不工作。或者页面根本加载不出来,因为 Vite 拒绝了你的隧道主机名。一旦知道往哪看,两者都是一行配置就能解决。

问题 1:“Blocked request. This host is not allowed.”

Vite 5+ 默认加入了主机检查保护。如果你打开隧道 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 穿隧道

三个真实理由:

  • 移动测试。在手机上打开 URL,看到带 HMR 的同一个 build。比共享屏幕或逐设备模拟器更好。完整模式参见 用隧道做移动测试
  • 分享进行中的工作。把链接发给设计师或 PM,他们就能实时看到你的分支。无需部署步骤。
  • 需要 HTTPS 的 OAuth 和 Webhook 流程。由 Vite 提供的前端要与 Stripe(仅 redirect)、Auth0 等对接。mkcert vs 隧道 讲了如何选择。

SvelteKit、Astro、SolidStart 都用 Vite

上面的配置适用于任何把 Vite 作为开发服务器的框架。SvelteKit 的 vite.config.js 形状相同。Astro 有自己的 astro.config.mjs,里面有一个 vite 子对象——把相同的 server 选项放到那里。SolidStart、Nuxt 3(经由 Vite)和 Qwik City:同一模式。

生产构建是另一回事

以上都是开发服务器的配置。当你运行 vite preview 或提供已构建的 bundle 时,这些都无关紧要,因为没有 HMR,也没有主机检查中间件。此时隧道只是在转发静态文件。

一些小事

  • 严格主机 CORS。如果你的前端访问另一个源上的 API(不同的 localhost 端口,或单独的 API 隧道),请在 API 侧设置 CORS。除非你通过 server.proxy 指示,Vite 默认不做代理。
  • WebSocket 密集的应用。Vite HMR 是一个 WebSocket。如果你的应用为游戏状态、聊天或实时数据使用了另一个 WebSocket,那个是独立的,也需要在你的客户端代码中配置为使用隧道 URL。
  • env 文件里的隧道 URL。当前端需要知道自己的公网地址时,我们把当前隧道 URL 作为 VITE_PUBLIC_URL 放进 .env.localimport.meta.env.VITE_PUBLIC_URL 在客户端读取它。

分步操作

  1. server.hostallowedHostshmr 块加到你的 Vite 配置中。
  2. 重启开发服务器。
  3. 运行 npx portpreview 5173(或 Vite 使用的端口)。
  4. 在浏览器或手机上打开 HTTPS URL。
  5. 编辑一个组件。确认 HMR 在不整页刷新的情况下更新页面。

如果 HMR 没更新,打开浏览器控制台——Vite 会记录 WebSocket 连接尝试,你能看到它尝试的 URL。这能告诉你 hmr.clientPort/protocol 的改动是否生效。

加入 PortPreview 等候名单,获得默认保留 WebSocket 升级的隧道。

常见问题

为什么 Vite 用“host is not allowed”阻止我的隧道 URL?
Vite 5+ 加入了默认拒绝未知主机名的主机检查。在 server 配置中加上 allowedHosts: ['.portpreview.dev'](或你的隧道域名)以接受隧道请求。
怎样让 Vite HMR 通过隧道工作?
在 vite.config.ts 中设置 hmr.clientPort: 443 和 hmr.protocol: 'wss'。这告诉 HMR 客户端通过隧道的 HTTPS/WSS 连接,而不是直接尝试访问 localhost——后者从你机器外部会失败。
这对 SvelteKit、Astro 和 Nuxt 有效吗?
有效。任何用 Vite 作为开发服务器的框架都采用相同的 server.host、allowedHosts 和 hmr 配置。Astro 把它嵌套在 astro.config.mjs 的 vite 之下;其他框架放在各自常规的 Vite 配置文件里。