react-hot-loader 和 webpack-dev-server 不会重新加载更改

Posted

技术标签:

【中文标题】react-hot-loader 和 webpack-dev-server 不会重新加载更改【英文标题】:react-hot-loader and webpack-dev-server don't reload changes 【发布时间】:2018-12-03 19:00:13 【问题描述】:

我尝试关注 react-hot-loader/getstarted 在我的 webpack 配置中启动并运行 react-hot-loader。当我对组件进行一些更改时,react-hot-loader 不会重新加载更改。我更新了 npm 脚本,将 react-hot-loader 添加到 babel 和 webpack 配置中,并将 module.hot.accept 添加到 index.jsx 中。

package.json

"scripts": 
    "dev": "webpack-dev-server -d --progress --colors --port 8090 --hot --inline",
  ,
    "dependencies": 
        "aphrodite": "^2.2.1",
        "bootstrap": "^4.1.1",
        "bootstrap-select": "^1.13.1",
        "classnames": "^2.2.5",
        "d3": "^3.5.17",
        "fixed-data-table-2": "^0.8.13",
        "font-awesome": "^4.7.0",
        "jquery": "^3.3.1",
        "js-cookie": "^2.2.0",
        "lodash": "^4.17.10",
        "moment": "^2.22.1",
        "popper.js": "^1.14.3",
        "react": "^16.3.2",
        "react-bootstrap-typeahead": "^3.1.3",
        "react-datetime": "^2.14.0",
        "react-dom": "^16.3.2",
        "react-hot-loader": "^4.3.3",
        "react-loadable": "^5.4.0",
        "react-modal": "^3.4.4",
        "react-redux": "^5.0.7",
        "react-router": "^4.2.0",
        "react-router-dom": "^4.2.2",
        "react-router-redux": "^5.0.0-alpha.9",
        "react-slidedown": "^1.3.0",
        "react-tippy": "^1.2.2",
        "react-toastify": "^4.0.1",
        "react-transition-group": "^2.3.1",
        "redux": "^4.0.0",
        "redux-saga": "^0.16.0"
      ,
      "devDependencies": 
        "autoprefixer": "^8.4.1",
        "babel": "^6.23.0",
        "babel-core": "^6.26.3",
        "babel-eslint": "^8.2.3",
        "babel-loader": "^7.1.4",
        "babel-plugin-syntax-dynamic-import": "^6.18.0",
        "babel-plugin-transform-async-to-generator": "^6.24.1",
        "babel-plugin-transform-class-properties": "^6.24.1",
        "babel-plugin-transform-object-rest-spread": "^6.26.0",
        "babel-polyfill": "^6.26.0",
        "babel-preset-env": "^1.6.1",
        "babel-preset-latest": "^6.24.1",
        "babel-preset-react": "^6.24.1",
        "css-loader": "^0.28.11",
        "eslint": "^4.19.1",
        "eslint-config-airbnb": "^16.1.0",
        "eslint-plugin-import": "^2.11.0",
        "eslint-plugin-jsx-a11y": "^6.0.3",
        "eslint-plugin-react": "^7.7.0",
        "file-loader": "^1.1.11",
        "http-server": "^0.11.1",
        "less": "^3.0.2",
        "less-loader": "^4.1.0",
        "node-sass": "^4.9.0",
        "npm-install-webpack-plugin": "^4.0.5",
        "postcss": "^6.0.22",
        "postcss-loader": "^2.1.4",
        "redux-devtools-extension": "^2.13.2",
        "sass-loader": "^7.0.1",
        "sass-resources-loader": "^1.3.3",
        "style-loader": "^0.21.0",
        "url-loader": "^1.0.1",
        "webpack": "^4.6.0",
        "webpack-cli": "^2.1.2",
        "webpack-dev-server": "^3.1.4",
        "webpack-merge": "^4.1.2",
        "webpack-notifier": "^1.6.0"
      

.babelrc


  "presets": [
    [
      "latest", 
        "es2015": 
          "modules": false
        
      
    ],
    "react"
  ],
  "plugins": [
    "transform-object-rest-spread",
    "transform-class-properties",
    "syntax-dynamic-import",
    "transform-async-to-generator",
    "react-hot-loader/babel"
  ]

webpack.config.js

const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const path = require('path');
const WebpackNotifierPlugin = require('webpack-notifier');

const TARGET = process.env.npm_lifecycle_event;
console.log(`target event is $TARGET`);

let outputFileName = 'app';
outputFileName += TARGET === 'prod' ? '.min.js' : '.js';

const common = 
  entry: ['babel-polyfill', 'react-hot-loader/patch', './index.jsx'],
  output: 
    publicPath: '/',
  ,
  module: 
    rules: [
      
        test: /\.js[x]?$/,
        exclude: /(node_modules)/,
        use: 
          loader: 'babel-loader',
        ,
      ,
    ],
  ,
  plugins: [
    new webpack.ProvidePlugin(
      jQuery: 'jquery',
      $: 'jquery',
      jquery: 'jquery',
      'window.jQuery': 'jquery',
    ),
    new WebpackNotifierPlugin(),
  ],
  resolve: 
    modules: [
      path.resolve('.'),
      path.resolve('script'),
      path.resolve('script', 'views'),
      'node_modules',
    ],
    extensions: ['.js', '.jsx', '.json'],
  ,
;

if (TARGET === 'dev' || !TARGET) 
  module.exports = webpackMerge(common, 
    devtool: 'eval-source-map',
    output: 
      filename: 'bundle.js',
      sourceMapFilename: '[file].map',
    ,
    module: 
      rules: [
        
          test: /\.scss$/,
          loaders: [
            'style-loader',
            'css-loader',
            
              loader: 'postcss-loader',
              options: 
                config: 
                  path: 'postcss.config.js',
                ,
              ,
            ,
            'sass-loader',
          ],
        ,
        
          test: /\.less$/,
          loaders: ['style-loader', 'css-loader', 'less-loader'],
        ,
        
          test: /\.css$/,
          use: ['style-loader', 'css-loader'],
        ,
        
          test: /\.(eot|ttf|svg|gif|png|jpg|otf|woff|woff2)$/,
          loader: 'url-loader',
        ,
      ],
    ,
    devServer: 
      contentBase: path.resolve(__dirname), // New
      historyApiFallback: true,
    ,
    plugins: [
      new webpack.DefinePlugin(
        'process.env.NODE_ENV': JSON.stringify('development'),
      ),
      new webpack.HotModuleReplacementPlugin(),
    ],
  );

index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import createHistory from 'history/createBrowserHistory';
import  createStore, combineReducers, applyMiddleware  from 'redux';
import  ConnectedRouter, routerReducer, routerMiddleware  from 'react-router-redux';
import  Provider  from 'react-redux';
import  AppContainer  from 'react-hot-loader';
import createSagaMiddleware from 'redux-saga';
import  composeWithDevTools  from 'redux-devtools-extension/developmentOnly';

import 'bootstrap';
import 'styles/custom.scss';

import App from 'App';
import reducers from 'state';
import sagas from 'sagas';

const history = createHistory();
const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  combineReducers(
    ...reducers,
    router: routerReducer,
  ),
  composeWithDevTools(applyMiddleware(routerMiddleware(history), sagaMiddleware)),
);

if (module.hot) 
  module.hot.accept('state', () => 
    store.replaceReducer(require('state').default);
  );


sagaMiddleware.run(sagas);

const render = (Component) => 
  ReactDOM.render(
    <AppContainer>
      <Provider store=store>
        <ConnectedRouter history=history>
          <Component />
        </ConnectedRouter>
      </Provider>
    </AppContainer>,
    document.getElementById('app'),
  );
;

render(App);

if (module.hot) 
  module.hot.accept('App', () =>  render(App); );

index.html

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8">

    <title>Test</title>

    <meta name="description" content="">

    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

</head>
<body>

    <div id="app">

    </div>

  <script type="text/javascript" src="/bundle.js"></script>

</body>
</html>

【问题讨论】:

【参考方案1】:
    您可以使用react-scriptreact-app-rewire-hot-loader

    你可能不会使用react-hot-loader/babel

     test: /\.(js|jsx)$/,
    include: paths.appSrc,
    loader: require.resolve("babel-loader"),
    options: 
      // This is a feature of babel-loader for webpack (not Babel itself).
      // It enables caching results in ./node_modules/.cache/babel-loader/
      // directory for faster rebuilds.
      cacheDirectory: true,
      plugins: ["react-hot-loader/babel"]
      ,
    
    

【讨论】:

react-hot-loader/babel 定义在.babelrc【参考方案2】:

您是否尝试过将根组件导出为热组件:

import  hot  from "react-hot-loader"
const App = () => <h3>Hello World</h3>
export default hot(module)(App)

【讨论】:

【参考方案3】:

您定义了两次Hot Module Replacement。您在package.json 中定义了--hot 参数,然后在webpack.config.js 中定义了new webpack.HotModuleReplacementPlugin()。你应该只定义一次。

【讨论】:

以上是关于react-hot-loader 和 webpack-dev-server 不会重新加载更改的主要内容,如果未能解决你的问题,请参考以下文章

如何让 react-hot-loader 与 webpack 2 和 webpackDevMiddleware 一起工作?

无法使 react-hot-loader 和 webpack-dev-server 与 react-router 一起工作

react-hot-loader: 未检测到 react-????-dom 补丁

React.lazy 和 react-hot-loader 遇到的两个坑

如何让 react-hot-loader 使用动态导入?

react-hot-loader 3.0于1.3的区别