# 模块热替换HMR
HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。
原理:webpack-dev-server会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket);
- HMR通过如下几种方式,来提高开发的速度:
- 不重新加载整个页面,这样可以保留某些应用程序的状态不丢失;
- 只更新需要变化的内容,节省开发的时间;
- 修改了css、js源代码,会立即在浏览器更新,相当于直接在浏览器的devtools中直接修改样式;
- 如何使用HMR呢?
- 默认情况下,webpack-dev-server已经支持HMR,我们只需要开启即可;
- 在不开启HMR的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是live reloading;
module.exports = {
// 其他省略
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)默认为true
},
};
css修改时会自动更新对应文件,页面修改css部分不会重新全部加载
js修改则需要通过module.accept处理,不处理的话会默认刷新页面而不是更新对应模块
# module.hot.accept
# w5写法
注意:devServer路径和output路径需要一致
const {HotModuleReplacementPlugin} = require("webpack");
module.exports = {
entry: "./src/main.js",
// 不适用也可以正常工作,如果出现HMR失效可以尝试开启
target:'web',// 模式和devserver中的hot最好同时都要设置进行热重载
output: {
path: path.resolve(__dirname, "./build"),
filename: "ugly.js",
},
devServer: {
static: {
// 注意路径和output一致
directory: path.join(__dirname, './build')
},
hot: true
},
mode:'development',
plugins:[
// 不适用也可以正常工作,如果出现HMR失效可以尝试开启
// new HotModuleReplacementPlugin()
]
}
// 注意后续版本是否支持module.hot,如果不支持,可尝试import.meta.webpackHot
if (module.hot) {
module.hot.accept("./js/element", function(){
console.warn('更新了',new Date().getSeconds())
})
}
if (import.meta.webpackHot) {
import.meta.webpackHot.accept("./demo.css", () => {
console.log("模块发生更新了2!");
},err=>{
console.warn(err,'err')
})
}
对于js,配置了,但是如果修改js里某个值,要更新就需要监听这个文件
import number from "./number"//还是需要引入一次
if(module.hot){
module.hot.accept("./number",()=>{
//修改监听,不需要可不写这个函数
})
module.hot.accept("./sum")
...
}
webpack-dev-server中代码根据hot是否为true,会去调用 webpack.HotModuleReplacementPlugin(),这样新版本的就不需要手动去添加热更新插件,但是如果使用别的工具,那么可能如果没有对应的配置,还需要手动添加热模块更新
if (this.options.hot) {
const HMRPluginExists = compiler.options.plugins.find(
(p) => p.constructor === webpack.HotModuleReplacementPlugin
);
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓老版本写法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
const webpack = require('webpack')
devServer:{
contentBase:'./zip',
open:true,
hot: true, // 热重载
hotOnly:true//如果热重载失效,页面不主动刷新
},
......
plugins:[
new webpack.HotModuleReplacementPlugin()
],
module.hot.accept(
dependencies, // 可以是一个字符串或字符串数组
callback // 用于在模块更新后触发的函数
errorHandler // (err, {moduleId, dependencyId}) => {}
);
// or
import.meta.webpackHot.accept(
dependencies, // 可以是一个字符串或字符串数组
callback, // 用于在模块更新后触发的函数
errorHandler // (err, {moduleId, dependencyId}) => {}
);
# 框架的HMR
比如开发Vue、React项目,修改了组件,希望进行热更新,不需要手动的去调用module.hot.accept
- 比如vue开发中,我们使用vue-loader,此loader支持vue组件的HMR,提供开箱即用的体验;
- 比如react开发中,有
React Hot Loader,实时调整react组件(目前React官方已经弃用了,改成使用reactrefresh);
new ModuleFederationPlugin({
name: "main_app",
filename: "remoteEntry.js",
exposes: {
"./search": "./src/search/search.vue"
},
remotes: {
lib_remote: "lib_remote@http://localhost:8085/remoteEntry.js"
},
shared: {
vue: {
eager: true,
singleton: true,
}
}
})