Hot Module Replacement热更新(webpack学习篇9)

模块热替换(HMR - Hot Module Replacement)作用:是指在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面时丢失的应用程序状态。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。

热更新配置:(在devServer对象里配置)

webpack.config.js

// 在这里做打包配置
const path = require('path'); // 引入node的path模块(loader模块)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 引入热更新插件,为webpack中自带的插件
const webpack = require('webpack');

// Common.js语法
module.exports = {
  mode: 'development', // 默认模式为production,可不写,不写时打包运行命令行会有警告
  devtool: 'cheap-module-eval-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8080,
    hot: true, // 让webpack-dev-server开启热更新的功能
    hotOnly: true // 即便是hot配置(HMR)没有生效,也不让浏览器进行刷新,失效时不做其他处理
  }, 
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader'
      ]
    }]
  },
  plugins: [
  	new HtmlWebpackPlugin({
      template: './src/index.html'
    }), 
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin() // 实例化热更新插件
  ],
  output: {
    filename: 'dist.js', // 打包之后的输出文件
    path: path.resolve(__dirname, 'dist') 
  }
}

// 配置完之后,一定要重新执行打包,不然配置项不会生效
// 样式文件变化,页面只修改展示样式,不会进行页面的刷新操作,也不会更改之前js操作的内容。

配置项的作用:

  • hot: true ===> 让webpack-dev-server开启热更新的功能
  • hotOnly: true ===> 即便是hot配置(HMR)没有生效,也不让浏览器进行刷新 (失效时不做其他处理)
  • HotModuleReplacementPlugin为webpack自带的热更新插件,所以要直接引入webpack,在plugins配置项中进行实例化。

热更新的应用:

在css方面应用:

目录结构:

|--demo
	|--node_modules
	|--src
		|--index.js
		|--style.css
		|--index.html
	|--package.json
	|--package-lock.json
	|--webpack.config.js

src/style.css

div:nth-of-type(odd) {
  background: #2086d7;
}

src/index.js

import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);
btn.onclick = function() {
  var div = document.createElement('div');
  div.innerHTML = 'item'; 
  document.body.appendChild(div);
}

执行打包:

npm  run  start

页面展示效果如图:(点击新增按钮,新增item项之后的效果)
Hot Module Replacement热更新(webpack学习篇9)_第1张图片
此时,再去修改style.css里的样式:(把偶数行的背景色改为粉色)

div:nth-of-type(odd) {
  background: pink;
}

页面展示效果为:(没有刷新浏览器,只更改了样式)
Hot Module Replacement热更新(webpack学习篇9)_第2张图片
如果不开启热更新,修改样式之后,由于浏览器刷新,页面会恢复到初始状态,页面上只保留一个"新增"按钮,再去点击的时候,才会有不同颜色的item显示在页面中。

在js方面的应用:

目录结构:

|--demo
	|--node_modules
	|--src
		|--counter.js
		|--number.js
		|--index.js
		|--index.html
	|--package-lock.json
	|--package.json
	|--webpack.config.js

counter.js

function counter() {
  var div = document.createElement('div');
  div.setAttribute('id', 'counter');
  div.innerHTML = 1;
  div.onclick = function() {
    div.innerHTML = parseInt(div.innerHTML, 10) + 1
  }
  document.body.appendChild(div);
}

export default counter;

number.js

function number() {
  var div = document.createElement('div');
  div.setAttribute('id', 'number');
  div.innerHTML = 1000; 
  document.body.appendChild(div);
}
export default number;

index.js

import counter from './counter';
import number from './number';
counter();
number();

// 这里需要判断下是否开启了热更新,如果开启了,就只让number函数再执行一次,否则不会热更新
if(module.hot) {
  module.hot.accept('./number', () => {
    document.body.removeChild(document.getElementById('number'));
    number();
  })
}

本质上要实现HMR,都要写类似以上(判断是否开启热更新,单独执行某代码块)的代码,否则不会热更新。但在很多时候,我们开发过程中,并没有去写这样的代码,是因为在相应的loader中,已经帮我们实现了热更新的代码。如:

  • css-loader中同样也配置了热更新,也不需要自己额外添加代码
  • 我们使用的vue框架里,vue-loader里也已经配置了热更新,所以不需要额外添加代码

index.js中引入两个模块,如果不开启热更新,那么当一个模块里的数据变化了,就会导致页面刷新,使另一个模块内的数据也恢复到初始值,如果我们想一个模块里的js代码的变化,不影响另一个模块代码变更过的数据,每改一个js模块里的代码,只会更新当前模块的数据,不会影响其他js模块的数据。以上需求可借助HMR来实现,

执行打包:

npm  run  start

页面展示效果:(第一行数字带有点击事件,初始值为1,每点击一次数值会加1)
Hot Module Replacement热更新(webpack学习篇9)_第3张图片
当点击数字值增加为7时,去修改number.js模块里的代码,把1000修改为3000,此时页面不刷新,counter.js模块里的数字7也没有变化,只更改了当前模块修改的数据。如下图:
Hot Module Replacement热更新(webpack学习篇9)_第4张图片
这就是热更新的巧妙之处。? (如果不开启热更新,修改number.js里的代码后,由于页面会刷新,counter.js里的数字也会变成初始值1)

你可能感兴趣的:(Webpack)