9.模块热更新

950 阅读3分钟

1.什么是模块热更新

模块热替换(HMR - Hot Module Replacement)

作用:它允许在运行时替换,添加,删除各种模块,

当你对代码修改并保存后,webpack将会对代码进行重新打包,并将改动的模块发送到浏览器端,浏览器用新的模块替换掉旧的模块,去实现局部更新页面而非整体刷新页面, 而无需进行完全刷新重新加载整个页面。

其思路主要有以下几个方面:

  1.保留在完全重新加载页面时丢失的应用程序的状态
  2.只更新改变的内容,以节省开发时间
  3.调整样式更加快速,几乎等同于就在浏览器调试器中更改样式

2.使用场景

一般情况下,一个模块发生变化,比如只改变一个css文件,js文件没有变化,最后还是全部都重新载

热模块更新就会 保留js的状态,只改变css文件

3.启动HRM

1.HotModuleReplacementPlugin 插件是 Webpack 自带的,

 const webpack = require('webpack');
 
 plugins: [ webpack.HotModuleReplacementPlugin(),] 

2.直接通过 webpack-dev-server 启动 Webpack 的开发环境:

 devServer: {hot: true,}

4.热更新处理文件

1.样式文件:可以使用HRM功能,style-loader内部实现了

2.js文件:js文件默认不能使用HRM功能

     解决:修改js代码,添加支持HRM的代码
     注意:模块热更新,不能用来主入口文件里,只能用在分支上面
     

3.html文件:html文件默认不能使用HRM功能,同时还会导致问题:html文件不能更新,改变了东西不能在页面改变

     解决:修改entey入口,将html文件引入,依旧默认不能使用HRM功能
     entry: ["./src/js/index.js", "./src/index.html"],

4.1 js文件使用HRM

1.没有热更新的情况

这个例子只是把示例页面的功能简单介绍下,并且让你体会下每次修改代码都要重新刷新页面的痛苦。

  //改变timer.js的延迟时间时,计数会从0开始计数
 import { start } from './timer'
 start(Update, 0);
 function Update(i) {
root.textContent = '#' + i // 修改数值渲染
}

2.依赖模块的热更新

接下来的例子,展示在 index.js 如何处理其他模块的更新。

module.hot.accept() 告诉 Webpack,当前模块更新不用刷新

module.hot.decline() 告诉 Webpack,当前模块更新时一定要刷新

在热更新的机制中,以这种“声明”的方式告知 Webpack,

哪些模块的更新是被处理的,

哪些模块的更新又不被处理

//改变timer.js的延迟时间时,计数会接着开始
var root = document.getElementById('root')
var stop = start(onUpdate, 0)
 if (module.hot) {
module.hot.accept('./timer', function () {
    stop()
    stop = start(onUpdate, 0)
})
module.hot.decline('./foo')
 }
 function onUpdate(i) {
root.textContent = '#' + i // 修改数值渲染
 }

3.处理自身模块

module.hot.dispose() 用于注册当前模块被替换前的处理函数,并且回调函数接收一个 data 对象,可以向其写入需要保存的数据,这样在新的模块执行时可以通过 module.hot.data 获取到:

首先,模块执行时,先检查有没有旧模块留下来的数据,如果有,就恢复。

然后在模块被替换前的执行处理,这里就是记录数据、停掉现有的定时器:

做了这些处理之后,修改 index.js 的 onUpdate,使得渲染到页面的数值改变, 也可以在不刷新的情况下体现:

 //在index.js中改变,计时器也会接着计时,不会从0开始
  添加以下代码:
if (module.hot && module.hot.data) {
current = module.hot.data.current
}
module.hot.accept()
module.hot.dispose(data => {
data.current = current
stop()
})