解决使用自定义域名时webpack的devserver热更新失效的问题
背景
如今
webpack
几乎成为了前端应用不可或缺的工具,其强大的功能和生态,让我们能够做到很多以前想都不敢想的事情。在开发阶段,相信大家都会用到webpack
的devserver
工具,此工具可以实现热更新,即我们代码改变后,实时进行编译,并实时更新页面上的对应视图,已达到代码更改,页面立即生效的效果,极大提升了开发效率。然而,近期,由于公司业务框架需要,我们不得不使用自定义域名,如:devxxx.kiner.com
,而不是使用localhost:8080
或127.0.0.1:8080
或0.0.0.0:8080
,由此而产生了一个问题:我们亲爱的热更新失效了,改代码之后,还是会实时编译,但是需要刷新浏览器才能生效。为此,笔者研究了一下webpack
的devserver
源码,找到了解决方案,再次分享一下,避免后来者入坑
问题
因配置自定义域名导致热更新模块实时更新失效,要刷新网页才能看到更新
解决问题思路
-
热更新失效了,那我们就看看,
webpack
是通过什么原理实现热更新的呢?- 从上面的截图不难看出,当我是使用自定义域名是,控制台出现了报错,而我们的请求当中,也有一个异常请求。在
webpack
中,采用了websocket
的方式实现热更新,大概的原理是这样的:webpack
启动开发服务时会启动一个websocket
,并且在我们的网页上注入监听代码,一旦webpack
监听到我们项目中有文件发生了改变,就会触发实时编译,然后通过websock
实时通知网页他这一次更新改变了什么,网页接收到消息后,就会对更新的模块进行重新渲染,以达到实时更新的目的。
-
了解了
webpack
实时更新的原理之后,我们再来分析一下,为什么使用自定义域名之后,会导致我们的websocket
的连接失效呢。-
对比一下使用
localhost
的时候是怎样的。 -
从上图我们可以发现,其实两者的不同点就是域名和端口不一样,使用自定义域名后,连接变成了
ws://devquestionnaire.tomabc.cn/sockjs-node
,而使用localhost
时,则是:ws://localhost:3246/sockjs-node
-
那么,我们有没有办法在使用自定义域名的时候,让
websocket
的请求连接依然保持ws://localhost:3246/sockjs-node
呢?这样是不是就能够请求成功,解决我们的问题了呢?
-
-
通过上一步,我们基本找到的症结所在,现在,我们就要想办法,在使用自定义域名的时候,让我们的
websocket
的链接保持ws://localhost:3246/sockjs-node
。-
我们来看一下
devserver
的源码,发现,其实让我们没有显示的指定websocket
的host和port的时候,他会自动获取当前网页的host和port作为websocket
的host和port,因此就会出现上述情况。 -
既然发现了这一点,那就简单了,我们通过环境变量显示指定一下,是不是就可以解决问题了呢?
# 先安装一个cross-env模块,这样我们就可以更方便的设置环境变量 yarn add cross-env -D
接下来,在
package.json
的启动命令中增加环境变量{ ... "scripts": { "start": "cross-env WDS_SOCKET_HOST=localhost WDS_SOCKET_PORT=3246 BUILD_ENV=development PORT=3246 react-app-rewired start" }, "devDependencies": { ... "cross-env": "^7.0.2", ... } }
-
最后,启动服务,看看效果
修改一下代码试一下
完美!!!
-