HMR(Hot Module Replacement)是webpack一个重要的特性,当代码文件修改并保存以后,webapck经过watch监听到文件发生变化,会对代码文件从新打包生成两个模块补丁文件manifest(js)和一个(或多个)updated chunk(js),将结果存储在内存文件系统中,经过websocket通讯机制将从新打包的模块发送到浏览器端,浏览器动态的获取新的模块补丁替换旧的模块,浏览器不须要刷新页面就能够实现应用的更新。javascript
本质上是一个容器,将webpack处理后的文件传递个服务器。前端
webpack-dev-middleware 是一个 express
中间件,核心实现两个功能:第一经过 file-loader
内部集成了node的 monery-fs/memfs
内部文件系统,,直接将资源存储在内存;第二是经过watch监听文件的变化,动态编译。vue
核心是给webpack提升服务端和客户端之间的通讯机制,内部使用windoe.EventSocurce实现。java
在webpack第一次打包的时候,除了代码自己以外,还包含一部分HMRruntime订阅服务代码,HMRruntime 订阅服务端的更新变化,触发HMR runtime API拉取最新的资源模块。node
webpack-hot-middleware实现页面的热重载。react
内置了webpack-dev-middleware和express服务器,利用webpack-dev-middleware提供文件的监听和编译,利用express提供http服务,底层利用websocket代替EventSource实现了webpack-hot-middleware提供的客户端和服务器之间的通讯机制。webpack
webpack --watch
启动监听模式以后,webpack第一次编译项目,并将结果存储在内存文件系统,相比较磁盘文件读写方式内存文件管理速度更快,内存webpack服务器通知浏览器加载资源,浏览器获取的静态资源除了JS code内容以外,还有一部分经过 webpack-dev-server
注入的的 HMR runtime代码,做为浏览器和webpack服务器通讯的客户端( webpack-hot-middleware 提供相似的功能
)。截图以下:浏览器接受到最新的 hotCurrentHash
,触发 hotDownloadManifest
函数,获取manifest json 文件。web
function hotDownloadManifest() { var request = new XMLHttpRequest(); var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json"; request.open("GET", requestPath, true); request.send(null); }
function hotDownloadUpdateChunk(chunkId) { var script = document.createElement("script"); script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js"; document.head.appendChild(script); }
HMR runtime 调用window["webpackHotUpdate"] 方法,调用hotAddUpdateChunkajax
var parentHotUpdateCallback = window["webpackHotUpdate"]; window["webpackHotUpdate"] = function webpackHotUpdateCallback(chunkId, moreModules) { hotAddUpdateChunk(chunkId, moreModules); if (parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules); };
hotAddUpdateChunk动态的更新代码模块,并调用hotUpdateDownloaded函数express
function hotAddUpdateChunk(chunkId, moreModules) { hotRequestedFilesMap[chunkId] = false; for (var moduleId in moreModules) { if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { hotUpdate[moduleId] = moreModules[moduleId]; } } if (--hotWaitingFiles === 0 && hotChunksLoading === 0) { hotUpdateDownloaded(); } }
hotUpdateDownloaded执行hotApply执行热重载
function hotUpdateDownloaded() { hotSetStatus("ready"); Promise.resolve() .then(function() { return hotApply(hotApplyOnUpdate); }) }