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); }) }