这篇文章就先把结论放在最前面啦,应该有利于阅读体验。前端
上回书说到git的用法,这篇文章就说下我学习webpack热更新原理的记录。vue
仍是由于上次面试的事,面试官问我是否知道webpack热更新的原理,我回答的是我使用vue-cli3构建项目,初始化的时候,webpack集成了一个能够监听文件变化,而且通知页面刷新的组件,他问能详细点吗,我...node
回家后,打开电脑,运行项目,打开浏览器控制台,选择 network ,先清除以前的加载记录。这时候去修改个人项目文件,保存,回来看下控制台,再修改,再回来看下控制台,这个时候让我发现了这个:webpack
一个hot-update.json文件和一个hot-update.js文件。有些年头的前端开发者会发现,hot-update.js返回的内容,怎么很像jsonp返回的内容。我忽然以为,我是否是要入门了,怀着激动的心情,我四处探索,如今按正确的时间线梳理一下。git
1.保持浏览器控制台,刷新网页,以下图,关键点在于 app.js,hot-update.js,websocket。github
2.打开app.js,很快能找到以下代码web
3.修改文件,控制台会变成以下面试
4.同时页面中也会插入一个scriptvue-cli
从以上截图,我先作个推论:wepack在启动的时候开启一个node服务,这个服务经过websocket与浏览器保持持续的通讯,在检测到文件发生变化时,服务端向浏览器发送一个json和一个js文件。同时每次服务端发送的消息的 hash 将做为下次 hot-update.json 和 hot-update.js 文件的 hash值。json
综合上面的分析,我以为我已经彻底掌握热更新流程,本文结束,嘻嘻睡了...
上面的推论是错的,也不是彻底错,只是细节错了。
一开始个人目标是直接查看webpack的源码,里面有一个hot的文件夹,在大概读了其中代码,只在里面找到了一些log输出和方法,没有找到在哪里调用的。感谢 HMR的原理 这篇文章让我找明了方向。代码是在webpack-dev-server的源码下面= =
下面就开始正文了:
当咱们构建项目的时候,webpack-dev-server会为咱们本身的js文件包上一层代码,加上两个依赖:
// 这个模块是新加的,咱们的入口就是 index,而这里加了一个模块,引用了 index,而且额外加了两行 require
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__("./node_modules/webpack-dev-server/client/index.js?http://localhost:8080");
__webpack_require__("./node_modules/webpack/hot/dev-server.js");
module.exports = __webpack_require__("./src/index.js");
/***/ })
/******/ })
复制代码
其中client/index.js主要负责创建socket通讯,为咱们提供一些监听方法等等,dev-server提供热更新的方法。
client/index.js 中有以下代码:
const onSocketMsg = {
hash: function msgHash(hash) { // 在 `hash` 事件触发的时候,把 `hash` 记下来
currentHash = hash;
},
ok: function msgOk() { // `ok` 事件触发的时候,表示server已经便已完成最新代码,
// ...
reloadApp();
}
};
// ...
function reloadApp() {
if (hot) {
log.info('[WDS] App hot update...');
// eslint-disable-next-line global-require
const hotEmitter = require('webpack/hot/emitter');
hotEmitter.emit('webpackHotUpdate', currentHash) // 触发这个事件
}
// ...
}
复制代码
hot/dev-server.js中:
hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash;
if (!upToDate() && module.hot.status() === "idle") {
log("info", "[HMR] Checking for updates on the server...");
check(); // 触发check方法
}
});
var check = function check() {
module.hot
.check(true) // 这里的check方法最终进入到webpack\lib\HotModuleReplacement.runtime.js文件中
...
}
复制代码
HotModuleReplacement.js中有:
function hotCheck(apply) {
...
return hotDownloadManifest(hotRequestTimeout).then(function(update) {
...
{
// 取到了 manifest后,就能够经过jsonp 加载最新的模块的JS代码了
hotEnsureUpdateChunk(chunkId);
}
...
});
}
复制代码
最终经过jsonp的方式加载,加载js的代码以下:
function hotDownloadUpdateChunk(chunkId) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.charset = "utf-8";
script.src = $require$.p + $hotChunkFilename$;
if ($crossOriginLoading$) script.crossOrigin = $crossOriginLoading$;
head.appendChild(script);
}
复制代码
到此为止,咱们就已经获得了新模块的JS代码了,下面就是调用对应的accpet回调。
本文结束,这些内容已经有不少人写过啦,本文只是用来记录本身的学习历程和加深本身的印象,若有错误,请指正!