我们在使用webpack(或者Rspack)的devServer
时,可以修改host
、port
等参数,以改变本地应用启动的监听地址及允许的域名,比如下面配置:
js
{
// ...
devServer: {
// 用来允许其他设备的访问
host: '0.0.0.0',
port: 3000,
// 允许所有的域名,包括代理转发过来的
allowedHosts: 'all',
client: {},
}
}
以上是devServer的基本配置,当然正常情况下你都可以不用管,webpack默认行为基本可以满足大多数的情况。
上面的client
属性用来配置浏览器端HMR如何与服务端交互,包括log level, 是否打出进度,是否错误时显示浮层以及websocket的自定义地址及协议。这里主要介绍下自己在使用client.webSocketURL
时遇到的坑,以及后面应该如何避免。
出现问题的场景
首先正常情况下,如果我们本地使用的是localhost
或者127.0.0.1
等ip时,无任何问题,都是ip直接访问即可,主要的一种情况是当你需要使用域名访问页面时(比如有些单点登录需要统一用域名访问)需要把域名指向到本地,我们一般有以下方案:
- 最直接的办法就是改host指向,利用SwitchHosts这种app
- 自定义DNS服务,如
dnsmasq
这类服务 - 使用代理App,例如Charles, Proxyman这种的
Map Remote
功能把域名指向到本地 - 浏览器插件代理
上面的方法各有优缺点,前面2种类似,但是经常会出现修改不生效,要清掉浏览器、系统各种dns缓存等情况,搞多了也很烦人;代理App的话没有缓存问题,主要是要做些配置,而且需要支持websocket的转发代理,幸好上面2个都支持🍻;浏览器插件就比较门槛低一些,无需安装其他服务或app,装个插件就搞定了,但是也存在一些问题:比如换个浏览器还得装一遍,HTTPS转发可能出问题,websocket看起来也有问题。大家可以根据自己的情况选择合适的解决方案。
话说回来笔者遇到的问题是当使用域名
时,ws的链接也是跟页面相同的域名,当然我可以使用代理App把websocket的域名也转到localhost。
但是我们希望ws直接ip直连,不要走域名,既然devServer
支持改ws链接,直接改配置不就行了:
js
{
// ...
devServer: {
host: '0.0.0.0',
client: {
webSocketURL: 'ws://0.0.0.0:3000/ws'
}
}
}
按照直觉ws也改成0.0.0.0
不就行了,大功告成,然而一试发现被打脸了,发出的ws请求还是域名,难道哪里配错了?又试了通过对象的方式传入:
js
{
// ...
devServer: {
host: '0.0.0.0',
client: {
webSocketURL: {
hostname: '0.0.0.0'
}
}
}
}
发现还是一样的问题,说明配的应该是对的,但是为啥不生效呢,继续查看了官方文档,也没特别说明,而且它也是这样写的🧐:
问题根源及解决办法
既然从文档上看不出来啥,只能从浏览器使用的client相关代码(node_modules/webpack-dev-server/client
)去看到底为啥链接不变,通过一层层往上找发现ws链接是在这个文件里生成的webpack-dev-server/client/utils/createSocketURL.js
,主要就是createSocketURL这个方法:
上图可以看到里面直接判断了hostname === "0.0.0.0"
,当为这个地址的时候并且在网页里时,直接用页面的hostname替代😭,我们也可以从上面的注释里看到为何要做这个判断,主要是为了支持在electron,ionic这类做桌面应用时的情况。
那我们的最简单的解决办法就是把0.0.0.0
改成127.0.0.1
或者其他局域网ip就可以直连了!