解决webpack热更新两次问题

今天在写代码的时候,发现webpack 的热更新功能执行了两次,每次刷新页面,就执行两次初始化函数,导致了bug,决定解决下。

看控制台可以发现,热更新的日志打印了两遍:

[HMR] Waiting for update signal from WDS...
[HMR] Waiting for update signal from WDS...
// console.log('init')
// console.log('init')

[WDS] Hot Module Replacement enabled.
[WDS] Hot Module Replacement enabled.

[WDS] Live Reloading enabled.
[WDS] Live Reloading enabled.

刚开始以为是启动了两个webpack-dev-server 导致的,但是关闭掉一个并没有解决问题,网上查了好久,也没找到多少有用的信息,最后用英文搜索了一会儿找到了一个帖子

文章里面说,是由于在html模板文件中,包含了下面这行代码导致的:

<script src="/bundle.js"></script>

原因是因为,html-webpack-plugin 插件,会自动帮我们注入script 标签,如果我们自己再引用一遍,那就会加载两遍了。听起来很有道理,我审查元素看了一下,果然文档中存在两个script 标签。

而我的模板文件是这样的:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app"></div>
<div id="module"></div>
<script src="/index.js"></script>
</body>
</html>

可以看到,截图中第一个js 引文是来自我写死的文件,第二个是插件帮我们注入的,后边还带着一串哈希值。找到原因就好办了,删除之后,果然重复加载的问题解决了。终于可以下班了,都11点了🤦‍♂️。

题外话

重复加载会导致什么问题呢?

最明显的是很多初始化函数会执行两次,如果是幂等的函数还好,只是影响性能;但如果函数不是幂等的,就会引入bug,和很多意想不到的问题。

举个栗子:

// utils.js
(function(){
	const log = console.log
    console.log = function (...parms) {
      log('info:', ...parms)
    }
})()

// main.js
console.log('hello')
// 预期 info: hello
// 实际 info:info: hello

原因就是,热更新执行了两次,导致这段代码执行了两次,第二次写的函数,其实已经被第一次加载的时候重写过一遍了。

有时候在写框架的时候,考虑到使用者可能会不小心将代码重复执行,比如上面的hot load 的问题。但如果代码重复执行了,可能会导致bug ,这个时候,需要保证代码重复执行,也是幂等的。可以像下面这样改写一下:

(function () {
  const log = console.log

  function newLog (...parms) {
    log('info:', ...parms)
  }
  newLog.isRewrite = true  //加个标记
  if (newLog.isRewrite) return
  console.log = newLog
})()

Leave a Comment

电子邮件地址不会被公开。 必填项已用*标注