【webpack 从入门到使用】热模块更新 HMR

93 阅读3分钟

概述:

模块热替换(hot module replacementHMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新。

注意:

HMR 并不适用于生产环境,HMR 只应当用于开发环境。更多详细信息, 请查看 生产环境 指南。

启动 HMR:

  1. webpackConfig.devServer中的 hot 选项设置为 true即可开启模块的热更新:
const config = {
  // ...
  devServer: {
    // ...
    hot: true, // 把这里设置成 true
  }
};

module.exports = config;
  1. package.json 命令行中添加 --hot 也可以开启模块的热更新
{
  "dev": "webpack-dev-server --config ./webpack.config.js --hot"
}

提示:

  1. webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。
  2. 如果你在技术选型中使用了 webpack-dev-middleware 而没有使用 webpack-dev-server,请使用 webpack-hot-middleware 依赖包,以在你的自定义服务器或应用程序上启用 HMR。

为 HMR 提供入口:

步骤:

  1. entry 选项中添加 hot 入口和配置 entry.devServerclient
  2. 关闭 devServer选项中的 clienthot
  3. plugins 选项中 HotMoudleRelacementPlugin

代码示例:

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

const config = {
  entry: {
    app: './src/index.js',
    // =================================> 1
    hot: 'webpack/hot/dev-server.js',
    // =================================> 1
    client: 'webpack-dev-server/client/index.js?hot=true&live-reload=true',
  },
  devtool: 'inline-source-map',
  devServer: {
  	static: './dist',
  	// =================================> 2
  	hot: false,
    // =================================> 2
  	client: false,
  },
  plugins: [
  	new HtmlWebpackPlugin({
      title: 'Hot Module Replacement',
  	}),
		// =================================> 3
		new webpack.HotModuleReplacementPlugin(),
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
};

module.exports = config;

直接配置 Node.js API

除了导出 webpackConfig 对象的创建方式,还可以直接使用 devServer 启动。

步骤:

具体步骤如下:

  1. 配置 webpack 的 config
  2. 调用 webpack(config) 生成 compiler
  3. compiler作为第二个参数实例化 webpackDevServer对象 server(第一个参数就是 devServer 中的配置)
  4. server.start()启动服务

代码示例:

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

const webpack = require('webpack');
const webpackDevServer = require('webpack-dev-server');

// 1. 配置选项
const config = {
  mode: 'development',
  entry: [
    // webpack 热更新的开发服务器入口 (需要引入一下)
    'webpack/hot/dev-server.js',
    // webpack-dev-server 客户端 API 的 chunk(需要引入一下)
    'webpack-dev-server/client/index.js?hot=true&live-reload=true',
    // 你自己项目的入口
    './src/index.js',
  ],
  devtool: 'inline-source-map',
  plugins: [
    // 定义热模块更新的插件
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      title: 'Hot Module Replacement',
    }),
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
};

// 2. 创建 compiler
const compiler = webpack(config);

// 3. 创建服务器
//     必须要手动创建 hot 和 client 这两个选项,所以先定义成 false
const server = new webpackDevServer({ hot: false, client: false }, compiler);

// 4. 启动项目
(async () => {
  await server.start();
  console.log('dev server is running');
})();

使用 HMR 实时加载样式:

借助于 style-loader,使用模块热替换来加载 CSS 实际上极其简单。

此 loader 在幕后使用了 module.hot.accept,在 CSS 依赖模块更新之后,会将其 patch(补丁) 打到 <style> 标签中。

框架层面的 HMR:

社区还提供许多其他 loader 和示例,可以使 HMR 与各种框架和库平滑地进行交互……

  • React Hot Loader: 实时调整 react 组件。
  • Vue Loader: 此 loader 支持 vue 组件的 HMR,提供开箱即用体验。
  • Elm Hot webpack Loader: 支持 Elm 编程语言的 HMR
  • Angular HMR: 没有必要使用 loader!直接修改 NgModule 主文件就够了,它可以完全控制 HMR API。
  • Svelte Loader: 此 loader 开箱即用地支持 Svelte 组件的热更新。