传统开发页面,每次更新的时候需要我们手动刷新浏览器才会更新。自从构建工具横空出世。我们可以通过热更新的方式来进行更新。通称HMR(hot module replacement),也就是模块热替换,当你每次需要更新代码的时候,不在需要手动刷新即可实现效果预览。
探究热更新是怎么实现之前,我们需要知道几样东西
sockjswebpack.HotModuleReplacementPluginmemory-fswebpack-dev-middlewarewebpack一些知识和一些底层知识,否则你估计会看不懂,并且属于懵逼状态,对于一些东西都给出了链接Compiler事件流
内存文件系统,webpack默认生成的文件会丢到内存中,并不会直接写入硬盘
中文文档
英文文档
这个是HMR实现核心,由webpack内部所提供的一个插件,该插件会提供一些方法,用于检查变更,并告诉你每次变更所生成的文件hash
用于发送socket请求,通知浏览器进行更改
webpack-dev-middleware会接收一个webpack所返回的一个compiler对象,然后调用compiler.watch监听文件更改,
我们知道webpack热更新的时候,并不会写入硬盘中,这是因为默认的情况下是写入内存的,因为内存的读取速度比硬盘会快很多,我们可以通过devServer.writeToDisk来修改
这样我们就可以知道文件是否更改,并且把文件存在了内存中,现在在回到webpack-dev-server
这里用webpack-dev-server进行举例,所有热更新原理基本类似。手写我们实现一个简单的webpack配置文件。
这是一个简单的流程图,不涉及任何复杂逻辑,这图中我们需要关注几个问题
为什么需要启动为什么需要添加webpack.HotModuleReplacementPluginwebpack-dev-server怎么知道文件发生了变化如何实现更新
现在我们有了上面的问题,来逐个去看下
为什么需要webpack.HotModuleReplacementPlugin
这个是webpack官方所提供的插件,该插件提供了一些方法,当我们启动的时候webpack会给每个文件注入moudle一个对象,这个对象里面有个module.hot对象,具体可以参考 中文文档 ,并且webpack每次重新构建的时候会生成一个hash,当我们把devServer.writeToDisk设置为true的时候,每次更改还会生成这2个文件。
hot-update.js是每次需要更新的文件hot-update.json下次更新需要生成的hash
webpack-dev-server怎么知道文件发生了变化
这个问题比较简单,webpack-dev-server启动的时候,初始化了express,并且把expres传递给了webpack-dev-middleware,webpack-dev-middleware也是webpack团队出品,devServer几乎所有api都是通过这个库去实现的。
webpack构建的时候会返回一个compiler对象,该对象会提供一个watch方法用来监听文件更改,而webpack-dev-middleware就是通过这种方法监听文件更改,
webpack.HotModuleReplacementPlugin也是一样的操作。并且每次重新构建的时候webpack-dev-server都会监听compiler的compile、invalid、done方法,会通知socket服务用于是否展示overlay(遮罩层)。
compile 在compilation生成之前,compilation是webpack每次重新编译所返回的一个对象invalid 编译失败done 编译成功如何实现更新
webpack-dev-server在启动的时候还会给entry添加2个文件
现在我们知道了每次构建所产生的hash,和产生的文件,但这时候还没办法热更新。我们可以记录每次构建所生成的hash,用于判断和当前的hash是否匹配,从而实现热更新,并且通知浏览器进行更新。
webpack-dev-server/client/index.js负责每次更新的状态,当状态为ok和warinings的时候会执行一个reloadApp方法,该方法会emit一个webpackHotUpdate事件,并把变更的文件hash传递出去,然后webpack/hot/devServer.js负责监听这个事件,当监听到该事件的时候,保存该文件hash,并且判断hash是否已更新并且module.hot.status为idle的时候,执行一个check方法,check会拿到一个需要更新的模块,如果有需要更新,则调用location.reload()方法,进行更新。
现在我们已经大概了解了热更新的过程。