Search code examples
reactjswebpackreduxreact-reduxwebpack-hmr

Stuck with webpack HMR configuration


I'm trying to correctly setup webpacks HMR, I'm developing a small app in order to learn how to use Redux in a React application.

I ran into a problem with webpack and the HMR plugin, when implementing the module.hot.accept function everything seems to work fine, but I've noticed it that when I modify a dependency of my App component it only re-renders the view when I don't pass any dependency argument to module.hot.accept as specified in webpack's docs.

This is what the documentation says I should do:

module.hot.accept(
  dependencies, // Either a string or an array of strings
  callback // Function to fire when the dependencies are updated
)

This is what I'm trying to do, this doesn't work.

module.hot.accept('./components/App', () => {
  render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('root')
  )
})
module.hot.accept('./reducers', () => {
  // Reconfigure the store
})

This one works

module.hot.accept(() => {
  // Render function
})

So let's say my App component, the one I render as child of the <Provider> imports a Header component and just renders like so:

const App = () => (
  <div>
    <Header />
  </div>
)

then if I edit Header the browser will only re-render the view if there's no dependency in module.hot.accept

The problem here is that if I don't pass any dependency it will try to reload my store object and that fires this warning: <Provider> does not support changing 'store' on the fly, I want to properly configure webpack so it only updates the store object when I change things on my reducers and the view when I make changes to my components or containers.

* Edit * Little bit of extra info, webpack seems to be aware of updates bc it logs in console the updated modules, however doesn't rerenders anything.

This is my webpack.config.js

const path = require('path')
const webpack = require('webpack')

const namedModules = new webpack.NamedModulesPlugin();
const hotModuleReplacement = new webpack.HotModuleReplacementPlugin();

const config = {
  context: path.resolve(__dirname, 'src'),
  entry: './index.jsx',
  devtool: 'eval-source-map',
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    filename: 'bundle.js'
  },
  module: {
    rules: [{
      test: /\.(js|jsx)$/,
      include: path.resolve(__dirname, 'src'),
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            ['env', {'es2015': {'modules': false}}],
            'react'
          ],
          plugins: [
            'transform-object-rest-spread',
          ]
        }
      }]
    }]
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json', '*'],
    modules: [
      'node_modules'
    ]
  },
  plugins: [
    namedModules,
    hotModuleReplacement
  ],
  devServer: {
    port: 9000,
    host: 'localhost',
    inline: true,
    hot: true
  }
}

module.exports = config

Thanks in advance, fine developers.


Solution

  • So it was the babel configuration as I thought, you need the option modules: false in the babel configuration so it lets webpack handle the modules, it is a noob mistake but man, it drove me crazy for days.

    Turned out I was doing something wrong in this line of the babel presets:

    ['env', {'es2015': {'modules': false}}]
    

    the correct configuration is:

    ['env', {modules: false}]