一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前言
很多前端的同学在学Webpack的时候初次接触到HMR的概念,起初只是觉得这个玩意听起来挺nb的,但是概念还是会有一些模糊,因为平时像我们这些在校生接触前端做做项目直接就上手Vue、React这些框架了,确实基于框架的开发体验会更加舒畅,可以不需要刷新浏览器实时查看源代码更改页面变化后的结果。其实这些底层都是脚手架帮你做的,我们还是有必要去了解一下HMR这个概念的,毕竟Webpack官方给这个功能赋予了高度的评价:
模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新。
一、Webpack自动刷新的问题
相信大家在阅读本文之前已经了解了webpack-dev-server的基本用法和特性,它主要是为开发者用Webpack构建的项目提供了一个友好的开发环境和一个可以用来调试的开发服务器,具有 live reloading(实时重新加载) 功能。
尽管这个功能已经给我们提供了浏览器实时预览的效果,但我们在开发过程中还是会有一些不舒服的地方,比如下面这个文本编辑器:
然后,当我们再次修改代码css样式的时候会发现文本编辑器里的内容竟然消失了!
万一我们在开发过程中编辑了很长一段文本用来测试,但是修改样式后这些文本都消失了,需要再次输入,这显然是我们不希望看到的。我们希望在浏览器自动刷新后,文本编辑器里的内容也不会被清空,怎么实现呢?这就是我们接下来要讲的HMR技术了(模块热替换)。
二、模块热替换的概念
在正式介绍HMR之前,我想先引入机器中热拔插的概念,即在一个正在运行的机器上随时插拔设备,而机器的运行状态不会受到插拔设备影响,而插上的设备可以立即开始工作,举个🌰,个人PC上的USB端口就是可以热拔插的。
发现了吗,模块热替换和机器中的热拔插都有一个热字,其实它们的概念是共通的,都是在运行过程中的即时变换。Webpack中的模块热替换指的就是在应用运行过程中实时替换某个模块,而应用的运行状态不受影响。例如上文的编辑器案例,页面自动刷新导致页面状态丢失,为了解决这个问题,HMR只将修改的模块实时替换到应用中。
三、Webpack如何实现热模块替换
HMR这个功能已经集成在了webpack-dev-server中,可以直接修改webpack的配置文件的devServer开启HMR功能:
或者使用命令:
这样再次修改页面css样式,浏览器自动刷新,编辑器里的样式就不会被吃掉啦。
四、HMR的疑问
上面我们只是修改了css的样式,确实会有模块热更新的效果,但是当我们修改JS的模块代码又会出现什么奇怪的现象呢?
我们修改JS代码,希望页面自动刷新后alert(123),但是我们发现浏览器并没有预期的弹出123,也就是说没有触发热更新。这又是怎么一回事呢???
其实HMR并不是Webpack中开箱即用的,还需要我们做一些额外的操作才能使用HMR的功能,Webpack中的HMR需要手动通过代码处理热模块替换逻辑。
Q1.为什么CSS样式会进行热替换
这时候你也许会问,上面演示的例子中为什么CSS样式会进行热替换呢,我们也没有做什么额外的逻辑处理呀?看上去样式文件的热模块替换功能是开箱即用的,其实样式文件的热更新是loader去处理的,别忘了我们webpack打包css文件可是在module.rules中使用了style-loader和css-loader呀,贴一张loader的热更新逻辑的源代码吧:
Q2.凭什么样式可以自动处理
样式更新只需要覆盖之前的样式就能完成自动更新,逻辑比较简单。而开发者编写的JS代码逻辑比较复杂,是没有规律可循的,有可能一个JS模块导出的是一个对象、一个字符串、一个函数,另一个模块对导出的模块的使用方式也是不同的,webpack面对这些毫无规律的逻辑根本就不知道怎么更新后的模块,因此Webpack不能开箱即用般的帮我们实现通用的模块替换方案。
Q3.框架脚手架搭建的项目没有手动处理,但是JS依然可以热替换
这一条是来填一下前言提到的坑。使用过vue-cli和create-react-app这些脚手架的同学可能会问,为什么在框架中JS代码会有热更新的功能呢,明明我在项目中没有手动处理热更新呀?这是因为我们使用的是框架,我们在框架中每种文件都是有规律的,框架本身提供的就是一种规则。例如,在react中要求每个模块必须要导出一个函数或者是导出一个类,那有了这样一个规律,那么就可以实现一个通用的热模块替换办法。其实,通过脚手架创建的项目内部都继承了HMR方案,所以我们都不需要手动处理了。
综上所述,我们还需要手动处理JS模块更新后的热替换。
结语
有关如何处理JS模块热替换建议去查阅一下Webpack官网的热模块替换,可以使用Webpack提供的HMR API来实现,这里就不再详细赘述。
好了,关于HMR的介绍就介绍到这里,如果这篇文章对您有帮助的话,能不能给我留下一个小小的赞呢,愿与诸君共勉~