带有 webpack-dev-server 的 HMR 不会重新加载 (webpack 4)

HMR with webpack-dev-server doesn't reload (webpack 4)

我正在为静态站点开发我的新 JS 入门程序,我想要一个类似 create-react-app 的架构。我所有的 webpack 配置都基于 create-react-app webpack 配置,但使用的是 Webpack 4。

当我启动 start.js 脚本时,使用 hot: true 选项创建了一个使用节点 API 的新 WebpackDevServer,但是热重载根本不起作用。

这是我的 webpack 配置:

const webpack = require('webpack')

const autoprefixer = require('autoprefixer')
const path = require('path')
const paths = require('./paths')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const getClientEnvironment = require('./env')

// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/'

// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = ''

// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl)

// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
module.exports = {
  mode: process.env.NODE_ENV,
  entry: [require.resolve('./polyfills'), paths.appIndexJs],
  output: {
    pathinfo: true,
    filename: 'static/js/bundle.js',
    chunkFilename: 'static/js/[name].chunk.js',
    publicPath: publicPath,
    devtoolModuleFilenameTemplate: info =>
      path.resolve(info.absoluteResourcePath).replace(/\/g, '/')
  },
  resolve: {
    modules: ['node_modules', paths.appNodeModules].concat(
      // It is guaranteed to exist because we tweak it in `env.js`
      process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
    ),
    extensions: ['.js', '.json', '.jsx'],
    alias: {
      src: path.resolve(paths.appSrc),
      locales: path.resolve(paths.appSrc, 'locales'),
      app: path.resolve(paths.appSrc, 'app'),
      config: path.resolve(paths.appSrc, 'config'),
      components: path.resolve(paths.appSrc, 'components'),
      values: path.resolve(paths.appSrc, 'values'),
      utils: path.resolve(paths.appSrc, 'utils'),
      helpers: path.resolve(paths.appSrc, 'utils/helpers')
    }
  },
  module: {
    strictExportPresence: true,
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env',
                [
                  '@babel/preset-react',
                  {
                    pragma: 'h'
                  }
                ]
              ],
              cacheDirectory: true
            }
          },
          {
            loader: 'eslint-loader',
            options: { emitWarning: true }
          }
        ],
        exclude: /node_modules/,
        include: paths.appSrc
      },
      {
        test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
        loader: require.resolve('url-loader'),
        options: {
          limit: 10000,
          name: 'static/media/[name].[hash:8].[ext]'
        }
      },
      {
        test: /\.scss$/,
        use: [
          require.resolve('style-loader'),
          {
            loader: require.resolve('css-loader'),
            options: {
              modules: true,
              localIdentName: '[local]___[hash:base64:5]',
              importLoaders: 2,
              alias: {
                src: path.resolve(__dirname, '../src')
              }
            }
          },
          {
            loader: 'sass-loader',
            options: {
              includePaths: ['./src'],
              data: '@import "config.scss";'
            }
          },
          {
            loader: require.resolve('postcss-loader'),
            options: {
              ident: 'postcss',
              plugins: () => [
                require('postcss-flexbugs-fixes'),
                autoprefixer({
                  browsers: [
                    '>1%',
                    'last 4 versions',
                    'Firefox ESR',
                    'not ie < 9'
                  ],
                  flexbox: 'no-2009'
                })
              ]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      inject: true,
      template: paths.appHtml
    }),
    new webpack.NamedModulesPlugin(),
    new webpack.DefinePlugin(env.stringified),
    new webpack.HotModuleReplacementPlugin(),
    new CaseSensitivePathsPlugin(),
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ],
  node: {
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  },
  performance: {
    hints: false
  }
}

这是我的启动脚本:

'use strict'

process.env.BABEL_ENV = 'development'
process.env.NODE_ENV = 'development'

const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const paths = require('../config/paths')

const config = require('../config/webpack.config.dev')

const compiler = webpack(config)

const server = new WebpackDevServer(compiler, {
  contentBase: paths.appPublic,
  publicPath: config.output.publicPath,
  inline: true,
  hot: true,
  watchContentBase: true,
  // quiet: true
  historyApiFallback: true,
  stats: { colors: true }
})

server.listen(8080, 'localhost', () => {
  console.log('Starting server on http://localhost:8080')
})

如果你想测试这个项目,有一个repo on Github

通过向我的 webpack 开发配置添加两个新的入口点,HMR 正在运行。

入口点现在是:

'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/dev-server',
require.resolve('./polyfills'),
paths.appIndexJs

你可以查看参考文献Issue on Github