Vite 合并第二份配置却沿用第一份端口,检查 HMR 默认对象变异
受影响的 Vite HMR 兼容处理会给共享默认对象安装访问器,后续合并可能沿用第一次的端口。8.3.4 改用拷贝,需检查默认对象与两次合并结果。
共享一份 Vite 默认配置,先与端口配置合并,再与另一份配置合并,第二个结果竟沿用了第一次的端口,这时要检查默认对象有没有在第一次合并中被改写。受影响路径与 HMR 选项兼容处理有关,不能仅靠重启浏览器排除。
具体报告使用 Vite 8.3.1。旧 HMR 连接选项映射到 server.ws 时,兼容代码直接在传入的 server.hmr 对象上安装 getter 与 setter。这些访问器闭包读取第一次创建的 ws 配置,导致复用默认对象的后续合并受到前一次结果影响。对象表面仍像普通配置,读取属性时却已进入另一个配置实例。
可以用一个独立脚本检查实际装入的 Vite,不必启动开发服务器:
// check-vite-merge.mjs
import { mergeConfig } from 'vite';
const defaults = { server: { hmr: { host: 'localhost' } } };
mergeConfig(defaults, { server: { hmr: { port: 3000 } } });
const second = mergeConfig(defaults, {
server: { hmr: { protocol: 'wss' } },
});
console.log(Object.getOwnPropertyDescriptors(defaults.server.hmr));
console.log(second.server.ws);
关注默认对象是否凭空出现 port 访问器,以及第二个 ws 结果是否带上未要求的端口。只打印一次已经合并的结果,不足以证明 defaults 保持原样;问题需要跨两次调用观察。
Vite 8.3.4 包含修复:兼容访问器安装到 HMR 对象的浅拷贝,避免修改调用者保存的默认对象。先在分支固定版本,再运行上述脚本和项目原构建:
npm install -D vite@8.3.4
npm ls vite
node check-vite-merge.mjs
npm run build
预期 defaults 仍只有普通的 host 字段,没有新增 port 自有属性;第二个 server.ws 包含 host 与 protocol,不应继承第一次的 3000。项目原本就配置了端口时,验收应按那个原始值判断,不能把任何 port 都当成错误。
如果需要临时隔离配置复用,可改为每次重新创建 defaults,而不是共享同一对象。但应保留配置中函数、插件及其他不可序列化的值,不能用 JSON stringify/parse 当成通用深拷贝。升级修复后,也要检查项目自己的合并封装有没有主动写回输入对象。
最后以真实开发入口检查 WebSocket 连接和热更新,确认目标 host、端口与协议符合部署环境。脚本结果正确不代表反向代理或证书设置也正确;wss 仍需要对应服务链路支持。连接失败但 defaults 完整,应继续排查代理与网络,而不是把所有 HMR 故障都归入对象变异。


