# 模块热替换HMR

HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。

原理:webpack-dev-server会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket);

  1. HMR通过如下几种方式,来提高开发的速度:
    • 不重新加载整个页面,这样可以保留某些应用程序的状态不丢失;
    • 只更新需要变化的内容,节省开发的时间;
    • 修改了css、js源代码,会立即在浏览器更新,相当于直接在浏览器的devtools中直接修改样式;
  2. 如何使用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,
		}
	}
})
最后更新: 5/1/2023, 9:10:04 AM