【Webpack 性能优化系列(1) - HMR 热模块替换】

webpack系列文章:

webpack性能优化

webpack性能优化主要指两个环境:

  • 开发环境性能优化
  • 生产环境性能优化

除了前面的开发环境和生产环境配置,还有以下性能优化处理:

开发环境性能优化包括:

  • 优化打包构建速度
    • HMR
  • 优化代码调试
    • source-map

生产环境性能优化包括:

  • 优化打包构建速度
    • oneOf
    • babel缓存
    • 多进程打包
    • externals
    • dll
  • 优化代码运行的性能
    • 缓存(hash-chunkhash-contenthash)
    • tree shaking
    • code split
    • 懒加载/预加载
    • pwa

HMR 热模块替换

为什么要使用HMR 热模块替换功能?

我们回看一下前面总结的开发环境配置:

/*
  开发环境配置:能让代码运行
    运行项目指令:
      webpack 打包运行项目
      npx webpack-dev-server 启动webpack-dev-server
*/

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 处理less资源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 关闭es6模块化
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true
  }
};

下面我们看一下这种配置存在什么问题

运行指令:npx webpack-dev-server ,启动webpack-dev-server

然后在index.js文件中打印一段话:console.log('index.js文件被加载了~');
在这里插入图片描述
只要index.js文件重新被加载,就会打印上面那段话

现在去修改样式文件
在这里插入图片描述

#box {
  width: 400px;// 200px修改为400px
  height: 200px;
  background-image: url('../imgs/angular.jpg');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

修改之后,很明显整体页面被刷新,内容被重新打印了一次
在这里插入图片描述
意思就是:当我们修改css文件时,明明js文件没有变化,但js文件也被重新加载了一次,所以打包的时候,看似只修改了css文件,实际上是把js文件也重新打包了一次,这是一个问题。

再写一个模块:
在这里插入图片描述
在index.js中引入上面那个print模块,并且在下面调用一下:
在这里插入图片描述
效果:
在这里插入图片描述
发现模块被加载,并且模块的print方法被调用执行了

现在我们修改一下print.js文件,'hello print'改为`‘hello webpack’

console.log('print.js被加载了~');

function print() {
  const content = 'hello webpack';
  console.log(content);
}

export default print;

保存查看效果,可以发现整个页面被重新刷新了,所有代码重新执行:
在这里插入图片描述
这个意思就代表:假设以后我们有100个js模块,100个样式模块,如果只修改其中某一个模块,这整200个模块就需要重新打包,这个速度可以想想是非常慢的,更不要说以后的模块会越来越多,那打包情况只会越来越慢。

所以我们想实现这样的功能:如果只有一个模块发生变化,那么只需要修改这一个模块代码就足够了,其他模块理应是不变的

做这个功能要使用webpack的HMR 热模块替换

HMR: hot module replacement 热模块替换 / 模块热替换

作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度

HMR功能的使用非常简单,只需要在devServer里配置hot:true即可:

  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 开启HMR功能
    // 当修改了webpack配置,新配置要想生效,必须重新webpack服务
    hot: true
  }

修改配置后,运行指令:npx webpack-dev-server ,重新启动webpack-dev-server

开启HMR功能跟之前更新有什么区别?

首先打印结果这里已经显示HMR功能已经开启:
在这里插入图片描述
下面修改样式文件,保存,可以发现只更新一个样式文件,js文件并不会重新加载:
在这里插入图片描述
可以发现:样式文件可以使用HMR功能,之所以能使用是因为style-loader内部实现了~

这也是为什么我们在开发环境要使用style-loader,生产环境要用MiniCssExtractPlugin.loader提取成单独文件,因为开发环境借助style-loader能让性能更好,打包速度更快,但是上线的时候考虑性能优化,所以不能用

前面样式文件可以使用HMR功能,js文件行不行呢?

修改print.js文件,保存,发现整个页面被重新刷新了一遍,这一点可以知道js文件默认不能使用HMR功能

html文件可以使用HMR功能吗?

在html文件中修改一段代码:
在这里插入图片描述
保存后发现当开启HMR功能后,html文件改动后并没有任何变化:
在这里插入图片描述
html文件: 默认不能使用HMR功能,同时会导致问题:html文件不能热更新了~

通过修改entey入口,改成一个数组,把html文件引入就可以解决上面的问题了:

entry: ['./src/js/index.js', './src/index.html'],

修改配置后,打包运行项目
在这里插入图片描述
测试发现html文件也是没有HMR功能的,一旦html文件发生变化,整体页面就会重新刷新

那么html文件需要HMR功能吗?

html不像js文件,一个项目里会有很多个js模块,而运行的html只会有一个,一旦发生变化,就一定要变化,它只需要变化一个文件,既然一定要变化,那就没办法优化,所以html文件不用做HMR功能

前面讲到了js默认不能使用HMR功能,这并不代表js就不需要HMR功能,如何对js文件使用HMR功能?

用法:

if (module.hot) {
  // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效
  module.hot.accept('./print.js', function() {
    // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
    // 会执行后面的回调函数
    print();
  });
}

在这里插入图片描述
修改print.js,查看效果
在这里插入图片描述
可以发现,print.js会重新更新,但index.js不会变,即index.js不会重新加载,样式和结构也不会重新加载,这就是js文件的HMR功能的使用

注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。

为什么呢?

因为入口文件会将其他文件全部引入,一旦入口文件变化,其他文件重新引入,就会重新加载,这是没办法阻止的,所以入口文件是做不了HMR功能的,只能对入口文件引入的一些依赖或者其他文件做HMR功能。

比如修改入口文件下面的打印代码:
在这里插入图片描述
保存,可以发现所有东西都要重新打包构建:
在这里插入图片描述

参考

  • https://www.bilibili.com/video/BV1e7411j7T5?p=17&spm_id_from=pageDriver
  • 0
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论 4

打赏作者

圆圆01

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值