webpack hmr 流程总结
webpack-dev-middleware:- 主要读取静态资源文件返回给浏览器
webpack-hot-middleware:- 主要处理匹配/webpack_hmr路由之后返回Content-type为
text/event-stream;charset=utf-8的响应
- 主要处理匹配/webpack_hmr路由之后返回Content-type为
webpack-hot-middleware/client.js:new EventSource('/webpack_hmr')监听服务器主动推送的消息,如打包完成之后hash值,改变的模块等交由./process-update.js处理webpack-hot-middleware/process-update.js:执行module.hot.check(),等同于调用HotModuleReplacement.runtime 的hotCheck();接着调用hotDownloadManifest获取json文件上一次的hash.hot-update.json,返回的内容为
{"h":"fb3e9ba6fcd4f92f416c","c":{"app":true}}
// bundle.js 中定义了一些函数
function hotDownloadManifest(requestTimeout) {
/******/
requestTimeout = requestTimeout || 10000;
/******/
return new Promise(function (resolve, reject) {
/******/
if (typeof XMLHttpRequest === "undefined") {
/******/
return reject(new Error("No browser support"));
/******/
}
/******/
try {
/******/
var request = new XMLHttpRequest();
/******/
var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json";
/******/
request.open("GET", requestPath, true);
/******/
request.timeout = requestTimeout;
/******/
request.send(null);
/******/
} catch (err) {
/******/
return reject(err);
/******/
}
/******/
request.onreadystatechange = function () {
/******/
if (request.readyState !== 4)
return;
/******/
if (request.status === 0) {
/******/
// timeout
/******/
reject(/******/
new Error("Manifest request to " + requestPath + " timed out.")/******/
);
/******/
} else if (request.status === 404) {
/******/
// no update available
/******/
resolve();
/******/
} else if (request.status !== 200 && request.status !== 304) {
/******/
// other failure
/******/
reject(new Error("Manifest request to " + requestPath + " failed."));
/******/
} else {
/******/
// success
/******/
try {
/******/
var update = JSON.parse(request.responseText);
/******/
} catch (e) {
/******/
reject(e);
/******/
return;
/******/
}
/******/
resolve(update);
/******/
}
/******/
}
;
/******/
}
);
/******/
}
接着调用hotEnsureUpdateChunk()->hotDownloadUpdateChunk()
请求上一次的hash.hot-update.js返回一个jsonp立即执行函数
// bundler.js
function hotEnsureUpdateChunk(chunkId) {
/******/
if (!hotAvailableFilesMap[chunkId]) {
/******/
hotWaitingFilesMap[chunkId] = true;
/******/
} else {
/******/
hotRequestedFilesMap[chunkId] = true;
/******/
hotWaitingFiles++;
/******/
hotDownloadUpdateChunk(chunkId);
/******/
}
/******/
}
function hotDownloadUpdateChunk(chunkId) {
/******/
var script = document.createElement("script");
/******/
script.charset = "utf-8";
/******/
script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js";
/******/
if (null)
script.crossOrigin = null;
/******/
document.head.appendChild(script);
/******/
}
// app.e75837e14d1a14baef6f.hot-update.js
webpackHotUpdate("app", {
/***/
"./node_modules/_vue-loader@14.2.4@vue-loader/lib/template-compiler/index.js?{\"id\":\"data-v-4a0103ec\",\"hasScoped\":true,\"optionsId\":\"0\",\"buble\":{\"transforms\":{}}}!./node_modules/_vue-loader@14.2.4@vue-loader/lib/selector.js?type=template&index=0!./example/pages/button.vue": /*!****************************************************************************************************************************************************************************************************************************************************************************!*\
!*** ./node_modules/_vue-loader@14.2.4@vue-loader/lib/template-compiler?{"id":"data-v-4a0103ec","hasScoped":true,"optionsId":"0","buble":{"transforms":{}}}!./node_modules/_vue-loader@14.2.4@vue-loader/lib/selector.js?type=template&index=0!./example/pages/button.vue ***!
\****************************************************************************************************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/***/
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, "render", function() {
return render;
});
/* harmony export (binding) */
__webpack_require__.d(__webpack_exports__, "staticRenderFns", function() {
return staticRenderFns;
});
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c("div", [_vm._v("3")])
}
var staticRenderFns = []
render._withStripped = true
if (true) {
module.hot.accept()
if (module.hot.data) {
__webpack_require__(/*! vue-loader/node_modules/vue-hot-reload-api */
"./node_modules/_vue-hot-reload-api@2.3.4@vue-hot-reload-api/dist/index.js").rerender("data-v-4a0103ec", {
render: render,
staticRenderFns: staticRenderFns
})
}
}
/***/
}
)
})
// bundle.js
var parentHotUpdateCallback = window["webpackHotUpdate"];
/******/
window["webpackHotUpdate"] = // eslint-disable-next-line no-unused-vars
/******/
function webpackHotUpdateCallback(chunkId, moreModules) {
/******/
hotAddUpdateChunk(chunkId, moreModules);
/******/
if (parentHotUpdateCallback)
parentHotUpdateCallback(chunkId, moreModules);
/******/
}