在前端开发中,webpack-dev-server是一个非常常用的工具,它可以为我们提供热更新的功能,使得开发变得更加高效。那么,webpack-dev-server是如何实现热更新的呢?
在本文中,我们将深入探讨webpack-dev-server的热更新原理。我们将介绍热更新的概念、如何在webpack-dev-server中启用热更新、热更新的工作原理以及如何使用热更新提高前端开发效率。无论您是初学者还是有一定经验的前端工程师,本文都将为您提供有价值的信息。
webpack-dev-server
启动时,会先启动本地静态资源服务,然后在启动websocket
服务,
websocket
服务此时会和本地静态资源服务建立连接,
接着在webpack entry
里面加入本地服务和websocket
通讯的相关代码
jsx// 修改后的entry入口
// 在入口新增两个文件,就会一起打包到bundle文件中去,在线上运行。
{
entry: {
main: [
// 上面获取的clientEntry
'xxx/node_modules/webpack-dev-server/client/index.js?http://localhost:8080',
// 上面获取的hotEntry
'xxx/node_modules/webpack/hot/dev-server.js',
// 开发配置的入口
'./src/main.js'
]
}
}
这样就实现了双向通讯机制
jsxwebpack-dev-server:负责启动服务和前置准备工作 webpack-dev-middleware:负责本地文件的编译和输出以及监听。
当webpack-dev-middleware
监听到文件发生变化时,就会给浏览器发送ok和hash事件
还记得我们上面说的修改entry入口么? 这个文件会被打包到bundle.js中,并运行在浏览器中。
xxx/node_modules/webpack-dev-server/client/index.js?[http://localhost:8080](https://link.juejin.cn/?target=http%3A%2F%2Flocalhost%3A8080)
看一下这个核心代码:
jsx// webpack-dev-server/client/index.js
var socket = require('./socket');
var onSocketMessage = {
hash: function hash(_hash) {
// 更新currentHash值
status.currentHash = _hash;
},
...
...
ok: function ok() {
sendMessage('Ok');
// 进行更新检查等操作
reloadApp(options, status);
},
}
socket(socketUrl, onSocketMessage);
// webpack-dev-server/client/util/reloadApp.js
function reloadApp() {
if (hot) {
log.info('[WDS] App hot update...');
// hotEmitter其实就是EventEmitter的实例
var hotEmitter = require('webpack/hot/emitter');
hotEmitter.emit('webpackHotUpdate', currentHash);
}
}
reloadApp()方法中,利用了node.js
的EventEmitter
,发出webpackHotUpdate
消息,发出了这个消息之后,webpack
接下来会做什么呢?
我们之前entry入口中,除了新增 xxx/node_modules/webpack-dev-server/client/index.js?[http://localhost:8080](https://link.juejin.cn/?target=http%3A%2F%2Flocalhost%3A8080)
, 还有新增了一个文件:xxx/node_modules/webpack/hot/dev-server.js
那我们看看这个文件的内容:
jsx// node_modules/webpack/hot/dev-server.js
var check = function check() {
module.hot.check(true)
.then(function(updatedModules) {
// 容错,直接刷新页面
if (!updatedModules) {
window.location.reload();
return;
}
// 热更新结束,打印信息
if (upToDate()) {
log("info", "[HMR] App is up to date.");
}
})
.catch(function(err) {
window.location.reload();
});
};
var hotEmitter = require("./emitter");
hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash;
check();
});
但是module.hot.check
这个是来自哪里呢?他是来自webpackConfig
的hot值
利用上一次保存的hash值,调用 hotDownloadManifest
发送 xxx/hash-update.json
的ajax请求,调用hotDownloadUpdateChunl
发送 xxx/hash.hot-update.js
请求(JSONP)
热更新的核心在 hotApply 这个函数中。具体做了:
jsxvar queue = outdatedModules.slice();
while (queue.length > 0) {
moduleId = queue.pop();
// 从缓存中删除过期的模块
module = installedModules[moduleId];
// 删除过期的依赖
delete outdatedDependencies[moduleId];
// 存储了被删掉的模块id,便于更新代码
outdatedSelfAcceptedModules.push({
module: moduleId
});
}
复制代码
jsxappliedUpdate[moduleId] = hotUpdate[moduleId];
for (moduleId in appliedUpdate) {
if (Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
modules[moduleId] = appliedUpdate[moduleId];
}
}
复制代码
jsxfor (i = 0; i < outdatedSelfAcceptedModules.length; i++) {
var item = outdatedSelfAcceptedModules[i];
moduleId = item.module;
try {
// 执行最新的代码
__webpack_require__(moduleId);
} catch (err) {
// ...容错处理
}
}
本文作者:BARM
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!