基于webpack的热重载live reload和热更新HMR(上)

本文涉及的产品
视频直播,500GB 1个月
简介: 在前端应用框架中不管是react还是vue,官方都提供了相应的脚手架方便开发者快速入手,当我们在开发时修改某个js或者css文件时,webpack会自动编译我们的文件,我们刷新浏览器就可以看到编译后的文件。为此我们会想,如果我们修改保存之后,文件被编译、浏览器自动刷新、或者浏览器局部刷新(不刷新整个浏览器),这样的话多好。当然,基于webpack打包工具的相关库已经实现了。下面对此部分流程做简单的分析

基于webpack的热重载live reload和热更新HMR — 当文件被修改后如何让浏览器更新代码


在前端应用框架中不管是react还是vue,官方都提供了相应的脚手架方便开发者快速入手,当我们在开发时修改某个js或者css文件时,webpack会自动编译我们的文件,我们刷新浏览器就可以看到编译后的文件。为此我们会想,如果我们修改保存之后,文件被编译、浏览器自动刷新、或者浏览器局部刷新(不刷新整个浏览器),这样的话多好。当然,基于webpack打包工具的相关库已经实现了。下面对此部分流程做简单的分析


  • 热重载live reload: 就是当修改文件之后,webpack自动编译,然后浏览器自动刷新->等价于页面window.location.reload()


  • 热更新HMR: 热重载live reload并不能够保存应用的状态(states),当刷新页面后,应用之前状态丢失。举个列子:页面中点击按钮出现弹窗,当浏览器刷新后,弹窗也随即消失,要恢复到之前状态,还需再次点击按钮。而webapck热更新HMR则不会刷新浏览器,而是运行时对模块进行热替换,保证了应用状态不会丢失,提升了开发效率


相关版本选择:


  1. webpack 版本git checkout v2.7.0  版本


  1. webpack-dev-middleware 版本git checkout v1.12.2 版本


  1. webpack-dev-server 版本git checkout v2.9.7 版本


说明: 这里选择webpack的版本为V2,是因为之前debug webpack的打包流程时恰为v2的版本,那可能会问webpack-dev-server版本为什么是这个呢? 这里解释下,通过package.json中的字段peerDependencies可以选定版本,为此我选择了对应的最新版本 v2.9.7。同样webpack-dev-middleware版本选择也是一样的,主要看依赖关系。 附上webpack-dev-server库的package.json文件描述


"name": "webpack-dev-server",
"version": "2.9.7",
"peerDependencies": {
    "webpack": "^2.2.0 || ^3.0.0"  // 这里说明需要的版本号
 }


进入主题 demo是 webpack-dev-server  目录下面的examples/api/simple列子,只粘贴出关键代码,建议clone代码比对一下


server.js 入口文件


'use strict';
const Webpack = require('webpack');
const WebpackDevServer = require('../../../lib/Server');
const webpackConfig = require('./webpack.config');
const compiler = Webpack(webpackConfig);
const devServerOptions = Object.assign({}, webpackConfig.devServer, {
  stats: {
    colors: true
  }
});
const server = new WebpackDevServer(compiler, devServerOptions);
server.listen(8080, '127.0.0.1', () => {
  console.log('Starting server on http://localhost:8080');
});


const webpackConfig = require('./webpack.config');  文件如下


'use strict';
var path = require("path");
// our setup function adds behind-the-scenes bits to the config that all of our
// examples need
const { setup } = require('../../util');
module.exports = setup({
  context: __dirname,
  entry: [
   './app.js', 
   '../../../client/index.js?http://localhost:8080/', 
   'webpack/hot/dev-server'
  ],
  devServer: {  // 这里配置hot值决定当开发时文件被修改并保存后 更新模式为热更新HMR
    hot: true
  }
});


入口entry 包含'../../../client/index.js?http://localhost:8080/' 以及 'webpack/hot/dev-server' 作用分别是:前者是WebpackDevServer的客户端浏览器代码,通过sockjs-client来链接Server端进行通信,比如开发时代码修改后保存,WebpackDevServer会通过 webpack-dev-middleware 拿到webpack编译后的结果,通过websockets 发送消息类型给客户端浏览器。 后者是webpack热更新HMR的客户端浏览器代码,打包时会insert进去,作用是当浏览器收到websockets发过来消息后,如果webpackConfig配置了webpack.HotModuleReplacementPlugin插件,就会走热更新HMR模式


../../../client/index.js 文件如下


'use strict';
const socket = require('./socket');
let urlParts;
let hotReload = true;
// __resourceQuery  也就是../../../client/index.js后面的参数 http://localhost:8080/ 通过webpack 打包时候替换
if (typeof __resourceQuery === 'string' && __resourceQuery) {
  // If this bundle is inlined, use the resource query to get the correct url.
  urlParts = url.parse(__resourceQuery.substr(1));
} else {
  // ...
}
let hot = false;
let currentHash = '';
const onSocketMsg = {
  hot: function msgHot() {
    hot = true;
  },
  hash: function msgHash(hash) {
    currentHash = hash;
  },
  ok: function msgOk() {
    reloadApp();
  }
};
// 建立websockets 链接
socket(socketUrl, onSocketMsg);
function reloadApp() {
  if (isUnloading || !hotReload) {
    return;
  }
  // 如果webpackConfig 中配置devServer.hot 为true,就走热更新HMR的模式,结论可以通过webpack-dev-server 的lib/Server.js 文件逻辑得出
  if (hot) {
    const hotEmitter = require('webpack/hot/emitter');
    hotEmitter.emit('webpackHotUpdate', currentHash);
  } else { // 否则走热重载live reload 直接刷新浏览器
    applyReload(rootWindow, intervalId);
  }
  function applyReload(rootWindow, intervalId) {
    clearInterval(intervalId);
    log.info('[WDS] App updated. Reloading...');
    rootWindow.location.reload();
  }
}


const socket = require('./socket'); 文件如下


'use strict';
const SockJS = require('sockjs-client');
let sock = null;
function socket(url, handlers) {
  sock = new SockJS(url);
  sock.onclose = function onclose() {
    // 此处是重连的逻辑 省略...
  };
  sock.onmessage = function onmessage(e) { // 当收到Server端的websockets 消息后执行对应的消息类型逻辑
    // This assumes that all data sent via the websocket is JSON.
    const msg = JSON.parse(e.data);
    if (handlers[msg.type]) { handlers[msg.type](msg.data); }
  };
}
module.exports = socket;


相关文章
|
6天前
|
前端开发
配置 Webpack 实现热更新
【10月更文挑战第23天】还可以进一步深入探讨热更新的具体实现细节、不同场景下的应用案例,以及如何针对特定需求进行优化等方面的内容。通过全面、系统地了解 Webpack 热更新的配置方法,能够更好地利用这一功能,提升项目的开发效率和性能表现。同时,要不断关注 Webpack 及相关技术的发展动态,以便及时掌握最新的热更新技术和最佳实践。
|
6天前
|
缓存 监控 算法
提高 Webpack 热更新的性能
【10月更文挑战第23天】还可以进一步深入探讨热更新性能优化的具体案例、不同场景下的优化策略,以及与其他相关技术的结合应用等方面的内容。通过全面、系统地了解热更新性能优化的方法和技巧,能够更好地利用这一功能,为项目的成功开发提供有力保障。同时,要不断关注技术的发展动态,以便及时掌握最新的热更新技术和最佳实践。
|
6天前
|
监控 前端开发 JavaScript
Webpack 中 HMR 插件的工作原理
【10月更文挑战第23天】可以进一步深入探讨 HMR 工作原理的具体细节、不同场景下的应用案例,以及与其他相关技术的结合应用等方面的内容。通过全面、系统地了解 HMR 插件的工作原理,能够更好地利用这一功能,为项目的成功开发提供有力保障。同时,要不断关注技术的发展动态,以便及时掌握最新的 HMR 技术和最佳实践。
|
6天前
|
自然语言处理 前端开发 开发工具
webpack 热更新
【10月更文挑战第23天】Webpack 热更新是一项非常实用的技术,它为前端开发带来了极大的便利和效率提升。通过深入了解其原理和应用,开发者可以更好地利用热更新功能,提高开发质量和速度。
|
6月前
|
API 开发工具 开发者
webpack热更新原理
Webpack的Hot Module Replacement(HMR)提升开发效率,无需刷新页面即可更新模块。开启HMR需在配置中设`devServer.hot: true`。Webpack构建时插入HMR Runtime,通过WebSocket监听并处理文件变化。当模块改变,Webpack发送更新到浏览器,HMR Runtime找到对应模块进行热替换,保持应用状态。开发者可利用`module.hot` API处理热替换逻辑。
|
6月前
|
前端开发 测试技术 开发者
深入理解 Webpack 热更新原理:提升开发效率的关键
深入理解 Webpack 热更新原理:提升开发效率的关键
|
6月前
|
自然语言处理 JavaScript 前端开发
webpack 的热更新是如何做到的?原理是什么?
webpack 的热更新是如何做到的?原理是什么?
88 0
|
6月前
|
前端开发 JavaScript 算法
面试官:【webpack和vite的区别?vite一定比webpack快吗?vite的缺点是什么?webpack的热更新和vite的热更新区别?】
面试官:【webpack和vite的区别?vite一定比webpack快吗?vite的缺点是什么?webpack的热更新和vite的热更新区别?】
1259 0
|
资源调度 前端开发 JavaScript
配置多入口 Webpack 热更新失效? #120
配置多入口 Webpack 热更新失效? #120
176 0
|
移动开发 前端开发 JavaScript
Webpack 如何配置热更新 #96
Webpack 如何配置热更新 #96
253 0