likes
comments
collection
share

聊一聊Webpack的热更新(HMR)

作者站长头像
站长
· 阅读数 22

Webpack提供了一个很有用的功能,就是热更新(Hot Module Replacement,简称HMR)。热更新可以让我们在开发过程中,修改了某个模块的代码后,不需要刷新浏览器,就能看到最新的效果。这样可以大大提高开发效率和体验。那么,Webpack是如何实现热更新的呢?本文将从原理、运行机制和配置三方面来介绍。

热更新的原理

要实现热更新,首先需要有一个服务器(Server)和一个客户端(Client)。服务器负责监听文件的变化,并通知客户端。客户端负责接收服务器的通知,并根据需要替换或更新模块。Webpack提供了两种方式来实现这个功能:webpack-dev-serverwebpack-hot-middleware

webpack-dev-server

webpack-dev-server是一个基于express的轻量级服务器,它可以在本地启动一个静态资源服务器,并且支持热更新。webpack-dev-server内部使用了webpack-dev-middlewarewebpack-hot-middleware两个中间件。webpack-dev-middleware负责将webpack打包后的文件暂存到内存中,并提供给浏览器访问。webpack-hot-middleware负责建立一个WebSocket连接,用于将文件变化的信息推送给浏览器。

webpack-hot-middleware

webpack-hot-middleware是一个基于connect的中间件,它可以和任何基于connect或express的服务器配合使用,实现热更新功能。webpack-hot-middleware也是通过WebSocket来通信的,但是它不会将打包后的文件暂存到内存中,而是直接从硬盘读取。

运行机制

  1. 当源代码发生变化时,webpack会重新编译打包,并将变化的模块发送给客户端。
  2. 客户端接收到变化的模块后,会通过HMR runtimeHMR api来处理模块的替换。
  3. HMR runtime负责维护模块之间的依赖关系,以及通知HMR api进行模块的更新。
  4. HMR api负责根据模块的类型和接受状态,执行相应的替换逻辑,比如调用module.hot.acceptmodule.hot.dispose等方法。
  5. 如果模块的替换成功,页面就可以实现局部更新;如果模块的替换失败,或者涉及到不支持HMR的模块,页面就会自动刷新。

如何启用HMR

下面是Webpack以及Vue不同版本的开启方式:

Webpack配置

  1. 在entry入口文件中添加webpack-hot-middleware/client或者webpack/hot/dev-server,这样可以在浏览器端创建一个客户端对象,用于接收服务器的通知。
    // webpack.config.js
    module.exports = {
      entry: {
        app: ['webpack-hot-middleware/client', './src/index.js'],
      },
      // ...
    };
    
  2. 在plugins插件中添加new webpack.HotModuleReplacementPlugin(),这样可以在编译时为每个模块添加一些代码,用于支持热更新。
    // webpack.config.js
    const webpack = require('webpack');
    
    module.exports = {
      // ...
      plugins: [
        new webpack.HotModuleReplacementPlugin(),
        // ...
      ],
    };
    
  3. 在output输出中添加publicPath属性,指定打包后的文件在服务器上的访问路径。
    // webpack.config.js
    module.exports = {
      output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
      },
      // ...
    };
    
  4. 在devServer开发服务器中添加hot属性,设置为true,表示启用热更新。
    // webpack.config.js
    module.exports = {
      devServer: {
        contentBase: './dist',
        hot: true,
      },
      // ...
    };
    

Vue-Cli3

使用 Vue CLI 3 可以通过 vue.config.js 文件来配置 webpack。下面是在 vue.config.js 中启用 HMR 的示例代码:

module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.HotModuleReplacementPlugin(),
    ],
  },
  devServer: {
    hot: true,
  },
};

在上述代码中,我们在 configureWebpack 中添加了 HotModuleReplacementPlugin 插件,以启用热更新功能。在 devServer 中设置 hot 属性为 true,表示启用热更新功能。

需要注意的是,如果你在 Vue CLI 3 中使用了多个 webpack 配置文件,则需要在对应的配置文件中进行相应的配置。

Vue-Cli4

// vue.config.js
module.exports = {
  devServer: {
    hot: true,
  },
};

在 Vue CLI 4 及以上版本中,你不需要手动配置 HotModuleReplacementPlugin 插件,Vue CLI 会自动为你配置。

参考资料

Webpack HMR 原理解析