cheungseol / cheungseol.github.io

2 stars 0 forks source link

Webpack in Action (3) #11

Open cheungseol opened 7 years ago

cheungseol commented 7 years ago

hot-module-replacement 热模块替换

webpack 通过配置支持在运行时更新各种模块,而无需进行完全刷新。HMR 不适用于生产环境,应当只在开发环境使用。

有两种启用HMR的方式:

1. 配置 webpack-dev-server ,使用 webpack 内置的 HotModuleReplacementPlugin 插件

webpack.config.js:

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

  module.exports = {
    entry: {
     app: './src/index.js'
    },
    devtool: 'inline-source-map',
    devServer: {
      contentBase: './dist',
+     hot: true
    },
    plugins: [
      new HtmlWebpackPlugin({
        title: 'Hot Module Replacement'
      }),
+     new webpack.HotModuleReplacementPlugin()
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

或者是命令行方式修改 webpack-dev-server 的配置:webpack-dev-server --hotOnly

index.js: 修改 index.js 文件,当 print.js 内部发生变更时通知 webpack 接受更新的模块

import _ from 'lodash';
  import printMe from './print.js';

  function component() {
    var element = document.createElement('div');
    var btn = document.createElement('button');

    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    btn.innerHTML = 'Click me and check the console!';
    btn.onclick = printMe;

    element.appendChild(btn);

    return element;
  }

  document.body.appendChild(component());
+
+ if (module.hot) {
+   module.hot.accept('./print.js', function() {
+     console.log('Accepting the updated printMe module!');
+     printMe();
+   })
+ }

print.js: 更改 print.js 中 console.log 的输出内容,你将会在浏览器中看到如下的输出。

  export default function printMe() {
-   console.log('I get called from print.js!');
+   console.log('Updating print.js...')
  }

问题: 当HMR后,DOM 元素的事件仍然绑定在HMR之前的节点上,需要在 module.hot.accept 方法的回调中更新DOM节点。

事实上,一些style-loader 等 loader 会在后台使用 module.hot.accept 来修补(patch)