gaearon / react-hot-boilerplate

Minimal live-editing example for React
MIT License
3.91k stars 879 forks source link

[HMR] The following modules couldn't be hot updated: (Full reload needed) #103

Closed iamyardem closed 7 years ago

iamyardem commented 7 years ago

Hello there. I've configured our project with webpack-dev-middleware but still can't resolve this error. No matter which component I change, it shows me this error:

process-update.js:81 [HMR] The following modules couldn't be hot updated: (Full reload needed) This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.

babelrc file

{
  "presets": ["es2015", "stage-0", "react"],
  "plugins": ["react-hot-loader/babel"]
}

webpack.config file

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common.config');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const ROOT_PATH = path.resolve(process.cwd());

module.exports = merge(common, {
  devtool: 'eval',
  entry: {
    bundle: [
      'react-hot-loader/patch',
      'webpack-hot-middleware/client',
      'babel-polyfill',
      './src/client',
    ],
  },
  output: {
    path: path.resolve(ROOT_PATH, 'dist'),
    filename: 'bundle.js',
    publicPath: '/assets/',
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ExtractTextPlugin('bundle.css'),
  ],
  module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loaders: ['eslint'],
        include: path.resolve(ROOT_PATH, 'src'),
      },
    ],
    loaders: [
      {
        test: /(\.css|\.scss)$/,
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass?sourceMap'),
      },
    ],
  },
  postcss: [autoprefixer({ browsers: ['last 2 versions'] })],
});

webpack.common

const path = require('path');
const ROOT_PATH = path.resolve(process.cwd());

module.exports = {
  resolve: {
    extensions: ['', '.js', '.jsx'],
    alias: {
      containers: path.resolve(ROOT_PATH, './src/containers'),
      components: path.resolve(ROOT_PATH, './src/components'),
      'redux-base': path.resolve(ROOT_PATH, './src/redux-base'),
      utils: path.resolve(ROOT_PATH, './src/utils'),
      routes: path.resolve(ROOT_PATH, './src/routes'),
      config: path.resolve(ROOT_PATH, './src/config'),
      styles: path.resolve(ROOT_PATH, './src/styles'),
    },
  },
  module: {
    loaders: [{
      test: /\.(js|jsx)$/,
      loaders: ['babel'],
      include: path.resolve(ROOT_PATH, 'src'),
      exlude: path.resolve(ROOT_PATH, 'node_modules'),
    }],
  },
};

client.js (entry point)

/* eslint-disable react/jsx-filename-extension, global-require */
import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import { syncHistoryWithStore } from 'react-router-redux';
import { browserHistory } from 'react-router';
import routes from 'routes';
import configureStore from 'redux-base/configureStore';
import AppRootComponent from './AppRootComponent';

const store = configureStore();
const history = syncHistoryWithStore(browserHistory, store);

render(
  <AppContainer>
    <AppRootComponent
      store={ store }
      history={ history }
      routes={ routes }
    />
  </AppContainer>,
  document.getElementById('root')
);

if (module.hot) {
  module.hot.accept('./AppRootComponent', () => {
    // If you use Webpack 2 in ES modules mode, you can
    // use <App /> here rather than require() a <NextApp />.
    const NextApp = require('./AppRootComponent').default;

    render(
      <AppContainer>
        <NextApp store={ store } history={ history } routes={ routes } />
      </AppContainer>,
      document.getElementById('root')
    );
  });
}

AppRootComponent.jsx

import React, { PropTypes } from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router';
import 'normalize.css';
import 'styles/main.scss';
import DevTools from 'utils/DevTools';
import config from 'config';

// If you use React Router, make this component
// render <Router> with your routes. Currently,
// only synchronous routes are hot reloaded, and
// you will see a warning from <Router> on every reload.
// You can ignore this warning. For details, see:
// https://github.com/reactjs/react-router/issues/2182

const AppRootComponent = ({ store, history, routes }) => (
  <Provider store={ store } >
    <div>
      <Router history={ history } routes={ routes } />
      {!config.isProduction && <DevTools /> }
    </div>
  </Provider>
);

AppRootComponent.propTypes = {
  store: PropTypes.object,
  history: PropTypes.object,
  routes: PropTypes.node,
};

export default AppRootComponent;

routes.js

/* eslint-disable react/jsx-filename-extension */
import React from 'react';
import { Route, IndexRedirect } from 'react-router';
import { CoreLayout } from 'containers';
import { Counter } from 'components';

export default (
  <Route path="/" component={ CoreLayout }>
    <IndexRedirect to="counter" />
    <Route path="counter" component={ Counter } />
  </Route>
);

server.js

/* eslint-disable consistent-return */
import webpack from 'webpack';
import express from 'express';
import path from 'path';
import devMiddleware from 'webpack-dev-middleware';
import hotMiddleware from 'webpack-hot-middleware';
import webpackDevConfig from '../webpack.dev.config';
import config from './config';

export default () => {
  const app = express();

  if (config.isProduction) {
    // Use built bundle as static file for production
    app.use('/assets', express.static(path.resolve('dist')));
  } else {
    const compiler = webpack(webpackDevConfig);

    app.use(devMiddleware(compiler, {
      publicPath: webpackDevConfig.output.publicPath,
      historyApiFallback: true,
    }));

    app.use(hotMiddleware(compiler));
  }

  app.get('*', (req, res) => {
    res.sendFile(path.resolve('static/index.html'));
  });

  app.listen(config.port, 'localhost', (err) => {
    if (err) {
      return console.log(err);
    }

    console.log(`App listening at http://localhost:${config.port}/`);
  });
};

Did I miss something? I am using beta 6 version of react-hot-loader. Thanks for your answer :)

matias-casal commented 7 years ago

+1

calesce commented 7 years ago

You'll need to put routes.js in module.hot.accept, since that's the module that "links" to the rest of your components. See this example.

Also, this issue belongs in the React Hot Loader repository.