# HMR热更新原理

**原文链接：**[**https://zhuanlan.zhihu.com/p/30669007**](https://zhuanlan.zhihu.com/p/30669007)

先贴个图复习一下HMR的流程，这里是使用webpack的插件webpack-dev-server来实现，还可以通过node与webpack-hot-middleware、webpack-dev-middleware来实现，**可以参考：**[**https://zhuanlan.zhihu.com/p/30623057**](https://zhuanlan.zhihu.com/p/30623057)**：**

![](https://3888408026-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LgAR97naB5LLN11YQUv%2F-LgARCBqiK05WMt9Vl8b%2F-LgARPWF_ac_MCNmWEAb%2Fv2-f7139f8763b996ebfa28486e160f6378_hd.jpg?generation=1559265127935302\&alt=media)

## 整个理解可以为：

1. 当改变模块代码（某个js文件）时，服务端webapck-dev-server的中间件webpack-dev-middleware会调用服务端的webapck暴露在全局中的api，会用wacth监控文件的改变，然后将信息传递给服务端的webpack , 服务端的webapk将重新打包。
2. 服务端的webpack打包时，会把打包好的文件输出到内存中，也就是将文件输出系统（**outputFileSystem**）变成内存输出系统（**MemoryFileSystem**），在内存里找文件更快，也避免了代码写入文件的开销。
3. wetbapk-dev-middleware通过websocket与webapck-dev-server客户端建立连接，（可能会懵逼，webapck-dev-server不是开启服务的，属于服务端的吗？我的理解是，webapck-dev-servert它包含了客户端和服务端的，分别存在浏览器端【开发工具里的source应用里】和服务器端【在开启服务器时用到】），也就是webapck-dev-middleware 把服务端的webpack的打包信息（hash值，compile的done事件【打包结束】）通过websoket发给webpack-dev-server/client(客户端).
4. webapck-dev-server/client 接收到消息后并不会请求变化的模块的代码，也不会执行模块的更新。会先保存hash值，判断返回消息为ok,把消息传给客户端的webpack, webapck在根据热更新配置，没有配置就刷新页面。有就把执行客户端webapck方法。
5. 客户端webapck主要通过三个模块的配合来实现模块的替换，当监听到客户端的webpack-dev-server传递的消息时，客户端的webpack会调用webpack/lib/HotModuleReplacement.runtime（简称 HMR runtime）的check方法检查是否有新的更新。在check的过程中，主要调用两个方法，**hotDownLoadUpdateChunk【**&#x7528;jsonp的方法xi向后台请求新的模块代码】和**hotDowbloadmanifest【**&#x61;jax向后台请求文件列表消息，有就返回到浏览&#x5668;**】，chunk**过程将会返回请求到的模块代码和文件更新的消息到 HMR runtime ,HMRruntime会根据这些返回的消息来决定是刷新页面还是替换模块。
6. HNR runtime 用得到的新模块替换旧的模快。首先找到旧的模块\[outdatedModules]和 旧的模块依赖【outdatedDependencies】，从内存中删除，将新的模块添加到 modules 中，当调用 \_\_webpack\_require\_\_ (webpack 重写的 require 方法)方法的时候，就是获取到了新的模块代码了。
7. 然而我们的业务代码（自己写的代码），不知道模块发生了变化（新的替换了旧的），所以得在业务代码里添加模块更新后的函数。也就是是有module.hot.accept(),方法。
