Webpack HMR无法重新加载HTML文件

时间:2018-09-23 09:55:19

标签: javascript html node.js webpack config

我有一个简单的HMR设置,用于重新加载打字稿文件和postcss文件。而且它们运行良好,并且无需刷新页面即可重新加载模块。但是,当我更改HTML文件时,网站不会自行重新加载,并且HTML内容也不会被重新加载。

这是我的webpack配置文件:

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

module.exports = {
  entry: resolve(__dirname, 'src/main.ts'),
  output: {
    path: resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'awesome-typescript-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
          {
            loader: 'postcss-loader',
          }
        ]
      }
    ]
  },
  devtool: 'source-map',
  mode: 'development',
  plugins: [
    new HtmlWebpackPlugin({
      template: resolve(__dirname, './src/index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new CleanWebpackPlugin(resolve(__dirname, 'dist'))
  ],
  devServer: {
    contentBase: resolve(__dirname, 'dist'),
    port: 9000,
    hot: true,
    open: true,
    progress: true,
  }
}

2 个答案:

答案 0 :(得分:2)

问题是html-webpack-plugin不会对更改做出反应,也不会触发hmr。 为了实现这一点,您可以尝试执行以下操作:

const { resolve } = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
let devServer; // set below in devserver part

function reloadHtml() {
  this.plugin('compilation',
    thing => thing.plugin('html-webpack-plugin-after-emit', trigger));
  const cache = {};
  function trigger(data, callback) {
    const orig = cache[data.outputName];
    const html = data.html.source();
    if (orig && orig !== html)
      devServer.sockWrite(devServer.sockets, 'content-changed');
    cache[data.outputName] = html;
    callback();
  }
}

module.exports = {
  entry: resolve(__dirname, 'src/main.ts'),
  output: {
    path: resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'awesome-typescript-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
          {
            loader: 'postcss-loader',
          }
        ]
      }
    ]
  },
  devtool: 'source-map',
  mode: 'development',
  plugins: [
    reloadHtml,
    new HtmlWebpackPlugin({
      template: resolve(__dirname, './src/index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new CleanWebpackPlugin(resolve(__dirname, 'dist'))
  ],
  devServer: {
    before(app, server) {
      devServer = server;
    },
    contentBase: resolve(__dirname, 'dist'),
    port: 9000,
    hot: true,
    open: true,
    progress: true,
  }
}

如果得到:

DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead

您可以将reloadHtml更改为此:

function reloadHtml() {
  const cache = {}
  const plugin = {name: 'CustomHtmlReloadPlugin'}
  this.hooks.compilation.tap(plugin, compilation => {
    compilation.hooks.htmlWebpackPluginAfterEmit.tap(plugin, data => {
      const orig = cache[data.outputName]
      const html = data.html.source()
      if (orig && orig !== html) {
        devServer.sockWrite(devServer.sockets, 'content-changed')
      }
      cache[data.outputName] = html
    })
  })
}

答案 1 :(得分:1)

不确定是否是这种情况,但是如果您只想扩展当前的HMR配置以在外部html / view文件更改时重新加载浏览器,则可以使用{{3 }}。

也许您已经有了它,因为webpack-dev-server内部使用chokidar,但是如果找不到,请先使用npm或yarn安装它:

npm install chokidar --save
yarn add -D chokidar

然后在您的webpack配置中要求它:

const chokidar = require('chokidar');

然后在您的devServer配置中:

devServer: {
  before(app, server) {
    chokidar.watch([
      './src/views/**/*.html'
    ]).on('all', function() {
      server.sockWrite(server.sockets, 'content-changed');
    })
  },

还要检查chokidar以获得更多选项。

我正在Webpack4中使用它。不知道它是否适用于早期版本...

希望它可以帮助您或其他人寻找这种情况。