- 什么是热更新?
无需刷新整个页面的同时更新模块
- 作用
节省开发时间,提升开发体验
- 疑问
配置热更新
使用HotModuleReplacementPlugin插件或配置hot
$ npm install webpack webpack-dev-server --save-dev
devServer: {contentBase: path.resolve(__dirname, 'dist'),hot: true,historyApiFallback: true,compress: true},
plugins: {HotModuleReplacementPlugin: new webpack.HotModuleReplacementPlugin()}, // 此处可以不写:因为如果devServer中配置hot:true,webpack会自动添加此插件
使用
if (module.hot) {module.hot.accept();}
热更新原理
使用webpack-dev-server托管静态资源,同时以runtime方式注入客户端代码
浏览器加载页面后,建立websocket链接
webpack监听文件的变化,构建发生变更的的模块,确认变更范围
浏览器加载变更的模块
webpack运行时出发变更的module.hot.accept回调,执行变更逻辑
1. webpack-dev-server启动本地服务
根据script中webpack-dev-server命令在bin中找到外链,看看具体执行的文件,以我自己的项目为例,最终在<br />// node_modules/@webpack-cli/serve/bin/index.js
let compiler = webpack(config); // 1. 生成webpack编译主引擎,compiler可以启动webpack所有编译工作,以及监听本地文件的变化
// 2.启动本地服务
server = new Server(compiler, devServerOptions);
server.listen(devServerOptions.port, devServerOptions.host, (error) => {
if (error) {
throw error;
}
});
// node_modules/webpack-dev-server/lib/Server.js
class Server {
constructor() {
this.setupApp();
this.createServer();
}
setupApp() {
// 依赖了express
this.app = new express(); // 使用express启动本地服务,让浏览器请求本地的静态资源
}
createServer() {
this.listeningApp = http.createServer(this.app);
}
listen(port, hostname, fn) {
return this.listeningApp.listen(port, hostname, (err) => {
// 3. 启动express服务后,启动websocket服务,websocket可以建立本地和浏览器的双向通信,这样就可以实现当本地文件发生变化,立马告诉浏览器可以热更新代码啦
this.createSocketServer();
}
}
}
监听webpack编译结束
// node_modules/webpack-dev-server/lib/Server.js
// 绑定监听事件
setupHooks() {
const {done} = compiler.hooks;
// 监听webpack的done钩子,tapable提供的监听方法
done.tap('webpack-dev-server', (stats) => {
// 调用_sendStats,通过websocket给浏览器发送通知 ok和hash事件,这里可以拿到hash值,做检查更新逻辑
this._sendStats(this.sockets, this.getStats(stats));
this._stats = stats;
});
};
// 通过websoket给客户端发消息
_sendStats() {
this.sockWrite(sockets, 'hash', stats.hash);
this.sockWrite(sockets, 'ok');
}
监听文件的变化
每次修改代码,就会出发更新,因此需要监听本地代码的变化
主要是webpack-dev-middleware库实现的:本地文件的编译和输出以及监听
// node_modules/webpack-dev-middleware/index.js
compiler.watch(options.watchOptions, (err) => {
if (err) { /*错误处理*/ }
});
// 通过“memory-fs”库将打包后的文件写入内存
setFs(context, compiler);
