【问题标题】:Hot module replacement - Updating but not re-rendering热模块更换 - 更新但不重新渲染
【发布时间】:2017-02-24 19:00:29
【问题描述】:

我正在运行一个快速服务器,它将充当我的 React 应用程序的 API,该应用程序由 webpack-dev-server 捆绑和提供服务。

我正在尝试让热模块更换工作,并且快到了,当我对我的文件进行更改时,我在控制台中得到了这个:

但应用永远不会重新渲染,除非手动刷新。不知道这是否相关,但是当我更新我的 .scss 文件时,它会在没有手动操作的情况下刷新,并且会按照我的预期进行更新。

版本:

"webpack": "2.1.0-beta.22"

"webpack-dev-server": "2.1.0-beta.8"

"react-hot-loader": "3.0.0-beta.5"

我尝试了最新的 webpack,但它给了我无法克服的验证错误。

我正在通过 "webpack": "webpack-dev-server --port 4000 --env.dev" 运行 webpack,而我的 express 服务器正在 http://localhost:3000 上运行。

这是我的webpack.config.babel.js

const webpack = require('webpack');
const { resolve, join } = require('path');
const { getIfUtils, removeEmpty } = require('webpack-config-utils')

const getEntry = (ifDev) => {
  let entry

  if (ifDev) {
    entry = {
      app: [
        'react-hot-loader/patch',
        'webpack/hot/dev-server',
        'webpack-dev-server/client?http://localhost:4000/',
        './js/index.js'
      ],
      vendor: ['react']
    }
  } else {
    entry = {
      bundle: './js/index.js',
      vendor: ['react']
    }
  }

  return entry
}

const config = env => {
  const { ifProd, ifDev } = getIfUtils(env)

  return {
    entry: getEntry(ifDev),
    output: {
      path: resolve('./public/dist/'),
      publicPath: 'http://localhost:4000/',
      filename: '[name].bundle.js',
    },
    context: resolve(__dirname, 'assets'),
    devtool: env.prod ? 'source-map' : 'eval',
    devServer: {
      contentBase: resolve('./public/dist/'),
      headers: { 'Access-Control-Allow-Origin': '*' },
      publicPath: 'http://localhost:4000/',
      hot: true,
      noInfo: true,
      inline: true
    },
    bail: env.prod,
    module: {
      loaders: [
        { test: /\.scss$/, loaders: [ 'style', 'css', 'sass' ], exclude: /node_modules|lib/ },
        { test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
        { test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader' }
      ]
    },
    resolve: {
      extensions: ['.js', '.jsx']
    },
    plugins: removeEmpty([
      ifDev(new webpack.NoErrorsPlugin()),
      ifDev(new webpack.NamedModulesPlugin()),
      ifDev(new webpack.HotModuleReplacementPlugin()),

      new webpack.DefinePlugin({
        'process.env': { NODE_ENV: JSON.stringify((env.prod) ? 'production' : 'development') }
      }),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        minChunks: Infinity,
        filename: 'vendor.bundle.js'
      }),

      ifProd(new webpack.LoaderOptionsPlugin({
        minimize: true,
        debug: false
      })),
      ifProd(new webpack.optimize.UglifyJsPlugin({
        compress: { warnings: false },
        output: { comments: false },
        sourceMap: false
      }))
    ]),
  }
}

module.exports = config

这是我的.babelrc,我打电话给react-hot-loader

{
  "presets": [["es2015", { modules: false }], "stage-0", "react"],
  "plugins": ["react-hot-loader/babel"],
  "env": {
    "test": {
      "plugins": ["istanbul"],
      "presets": ["es2015", "stage-0", "react"]
    }
  },
  "sourceMaps": "inline"
}

【问题讨论】:

    标签: javascript webpack webpack-dev-server webpack-hmr hot-module-replacement


    【解决方案1】:

    HMR 自动适用于 CSS,因为 style-loader 支持开箱即用。

    对于 React,情况并非如此。你需要react-hot-loader

    用 npm 安装它,然后改变这个:

    { test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
    

    收件人:

    { test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'react-hot-loader', 'babel-loader' ] },
    

    如果你想了解更多,我推荐阅读“Webpack’s HMR & React-Hot-Loader — The Missing Manual”。

    【讨论】:

    • 我忘了在3.X 中添加我的.babelrc,我在其中调用react-hot-loader,它鼓励您将其从配置移至babel。
    【解决方案2】:

    使用 React Hot Loader v3 和 Babel 转换,您希望在组件的根目录(进行渲染或创建 Redux 提供程序的位置)执行此操作:

    render(
      <AppContainer>
        <Root
          store={ store }
        />
      </AppContainer>,
      document.getElementById('root')
    );
    
    if (module.hot) {
      module.hot.accept('./containers/Root', () => {
        const RootContainer = require('./containers/Root').default;
        render(
          <AppContainer>
            <RootContainer
              store={ store }
            />
          </AppContainer>,
          document.getElementById('root')
        );
      });
    }
    

    使用新版本的 Hot Loader,您必须通过 module.hot.accept 明确接受热更新。

    在更复杂的 Redux 项目中(使用路由和热重载减速器),您可以执行以下操作:

    /**
     * Starts the React app with the Router, and renders it to the given DOM container
     * @param  {DOMElement} container
     */
    export default function app(container) {
      const store = createStore(
        combineReducers({
          ...reducers,
          routing: routerReducer,
          form: formReducer,
        }),
        compose(
          applyMiddleware(
            routerMiddleware(hashHistory),
            thunkMiddleware,
            promiseMiddleware
          ),
          process.env.NODE_ENV !== 'production' && window.devToolsExtension ? window.devToolsExtension() : (param) => param
        )
      );
    
      if (module.hot) {
        module.hot.accept('./reducers', () => {
          const nextReducers = require('./reducers');
          const nextRootReducer = combineReducers({
            ...nextReducers,
            routing: routerReducer,
            form: formReducer,
          });
          store.replaceReducer(nextRootReducer);
        });
      }
    
      const history = syncHistoryWithStore(hashHistory, store);
    
      render({ store, history, container });
    
      store.dispatch(loadEventsWhenLoggedIn());
    
      if (module.hot) {
        module.hot.accept('./render', () => {
          const newRender = require('./render').default;
          newRender({ store, history, container });
        });
      }
    }
    

    (和 render.js)

    /**
     * Starts the React app with the Router, and renders it to the given DOM container
     * @param  {DOMElement} container
     */
    export default function render({ store, history, container }) {
      ReactDOM.render(
        <Provider store={store}>
          <div className='container'>
            <Routes history={history} store={store} />
          </div>
        </Provider>,
        container
      );
    }
    

    有关更多示例,您应该查看 Dan Abramov 的 Redux devtools 示例 repo,例如此文件:https://github.com/gaearon/redux-devtools/blob/master/examples/todomvc/index.js

    【讨论】:

      猜你喜欢
      • 2017-06-17
      • 1970-01-01
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      • 1970-01-01
      • 2020-12-12
      • 2019-09-22
      • 2017-06-28
      相关资源
      最近更新 更多