React-hot-loader: React Hot Loader does not reload components imported through a webpack alias

Created on 2 May 2017  路  14Comments  路  Source: gaearon/react-hot-loader

If you are reporting a bug or having an issue setting up React Hot Loader, please fill in below. For feature requests, feel free to remove this template entirely.

Description

When making changes to components that are imported to an application through an alias, the hot reloader does not pick up these changes.

Expected behavior

The reloader should pick up the changes as it does all other components.

Actual behavior

Nada. (Components are not hot reloaded. The reloader works if the component is referenced via full path.)

Environment

React Hot Loader version:
3.0.0-beta6

Run these commands in the project folder and fill in their results:

  1. node -v: v7.8.0
  2. npm -v: 4.2.0 (using yarn)
  3. yarn --version: 0.21.3

Then, specify:

  1. Operating system: OSX 10.11.6
  2. Browser and version: Chrome

Reproducible Demo

WILL UPDATE SOON

Other information

.babelrc

{
  "presets": [
    "react",
    "es2015",
    "stage-0"
  ],
  "plugins": [
    "react-hot-loader/babel",
    ["module-resolver", {
      "root": ["./client"],
      "alias": {
        "Shared": "shared",
        "Schemas": "schemas",
        "Utilities": "utilities"
      }
    }]
  ]
}

webpack resolve.alias

resolve: {
      extensions: ['.js', '.json'],
      alias: {
        ActionTypes: path.join(__dirname, 'client/constants/actionTypes.js'),
        ScreenSizes: path.join(__dirname, 'client/constants/screenSizes.js'),
        Matchers: path.join(__dirname, 'client/constants/matchers.js'),
        Assets: path.join(__dirname, 'client/assets'),
        Schemas: path.join(__dirname, 'client/schemas'),
        Shared: path.join(__dirname, 'client/shared'),
        Utilities: path.join(__dirname, 'client/utilities')
      }
    }

Most helpful comment

Lots and lots of troubleshooting later... it appears react-hot-loader is fickle when using other babel environment presets. When using the "env" preset and targeting older browsers, I couldnt get it to reload. The only change I finally made was using the "latest" preset and setting es2015 modules to false as suggested in the react-hot-loader minimal example. Sigh of relief...

{
  "presets": [
    [
      "latest", {
        "es2015": {
          "modules": false
        }
      }
    ],
    "react"
  ],
  "plugins": [
    "transform-object-rest-spread",
    "react-hot-loader/babel"
  ]
}

All 14 comments

I think I have this problem. Did you find a solution?

I am also having this issue and cannot seem to solve it.

@dethstrobe @sebinsua @jediofthecode
I was having this issue also, but have since resolved it.
I had aliased a folder as Parts in my web pack.config.js as below

resolve: {
    extensions: ['.js', '.jsx'],
    alias: { Parts: path.resolve(__dirname, 'src', 'parts') }
  }

This broke my hot reloading when I used the following in my main entry point

import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';

import Root from 'Parts/root';

const render = Component => {
  ReactDOM.render(
    < AppContainer >
      <Component />
    </AppContainer >,
    document.getElementById('root')
  );
};

render(Root);

if (module.hot) {
  module.hot.accept('./parts/root', () => {
    render(Root);
  });
}

The issue I found was that the module.hot.accept function then received 'Parts/root' as its parameter.

So to resolve the issue, I changed that part of the code to have 'Parts/root' as its parameter like below

import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';

import Root from 'Parts/root';

const render = Component => {
  ReactDOM.render(
    < AppContainer >
      <Component />
    </AppContainer >,
    document.getElementById('root')
  );
};

render(Root);

if (module.hot) {
-  module.hot.accept('./parts/root', () => {
+  module.hot.accept('Parts/root', () => {
    render(Root);
  });
}

That solved it for me.

So, this is related to webpack`s HMR, not react-hot-loader?

So, this is related to webpack`s HMR, not react-hot-loader?

@theKashey

I believe so... I am using react-hot-loader, however, I believe the module.hot.accept() function is from webpack HMR.
The thing is, at least in my case, it was not a bug at all, but merely that I was using it incorrectly.
If that is the case for the other people in this issue, then they can now solve their problem, and this issue can be closed....

@thtliife - so, the rule is simple - accept modules as you import them.
It is bit strange, as long my version of webpack(3) will trigger an error in case you used a wrong module name.

I am also having this problem :(. @thtliife your suggestion did not solve it for me. I currently only have webpack's module alias defined. I tried adding in the babel-module-resolver but that didn't change anything.

Lots and lots of troubleshooting later... it appears react-hot-loader is fickle when using other babel environment presets. When using the "env" preset and targeting older browsers, I couldnt get it to reload. The only change I finally made was using the "latest" preset and setting es2015 modules to false as suggested in the react-hot-loader minimal example. Sigh of relief...

{
  "presets": [
    [
      "latest", {
        "es2015": {
          "modules": false
        }
      }
    ],
    "react"
  ],
  "plugins": [
    "transform-object-rest-spread",
    "react-hot-loader/babel"
  ]
}

@jamesmfriedman - whats why I have opened https://github.com/gaearon/react-hot-loader/pull/608, to understand "what the f* is going on" somewhere underneath.

Hi
I'm trying to copy exactly the same example here:
https://webpack.js.org/guides/hot-module-replacement/
But it's not working.

  if(module.hot) {
      module.hot.accept('./print.js', () => {
          console.log(printMe.toString())
          document.body.removeChild(element);
          element = dasCouve();
          document.body.appendChild(element);
      });
  }

My printMe function is not updated and the module.hot.accept listener is only fired once no matter how many changes I make in the print.js file. In the network tab from Chrome I can see the new print.js being received:
screen shot 2017-08-31 at 10 47 27

My webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: {
      app: './src/index.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-map',
  devServer: {
    port: 3000,
    host: '0.0.0.0',
    hot: true,
    contentBase: './dist'
  },
  module: {
      rules: [
          {
              test: /\.js$/,
              use: 'babel-loader'
          },
          {
              test: /\.css$/,
              use: [
                  'style-loader',
                  'css-loader'
              ]
          }
      ]
  },
  plugins: [
      new HtmlWebpackPlugin({
          title: 'Output Management'
      }),
      new webpack.HotModuleReplacementPlugin()
  ]
};

Am I missing something? Thanks
@theKashey

@ThiagoMiranda - you missed the webpack.NamedModulesPlugin()
Without it you file is not "print.js", it is "39" as shown in network tab.

@theKashey
It didn't work. Now the console indeed shows me the name of the plugin but it remains the old code.
My .js is:

import printMe from './print.js';
import './style.css';

const dasCouve = () => {
    const element = document.createElement('div');
    const btn = document.createElement('button');

    btn.innerHTML = 'Clique aqui!!';
    btn.onclick = printMe;
    element.innerHTML = ['Sambatech', 'webpack', 'Babel '].join(' ');

    element.appendChild(btn);
    return element;
  }

  let element = dasCouve();

  document.body.appendChild(element);


  if(module.hot) {
      module.hot.accept('./print.js', () => {
          console.log('Aceitando a mudan莽a do printMe as');
          console.log(printMe.toString()) //Shows me always the same code from the first refresh
          document.body.removeChild(element);
          element = dasCouve();
          document.body.appendChild(element);
      });
  }

@ThiagoMiranda if you are using webpack 3 - it should work. In case of webpack 2 - you have to re-require all the stuff you need.
Please check ANY webpack's HRM guide.

I guess the plugins order in .babelrc is important too. This should resolve the issue:

"plugins": [
    ["module-resolver", {
      "root": ["./client"],
      "alias": {
        "Shared": "shared",
        "Schemas": "schemas",
        "Utilities": "utilities"
      }
    }],
    "react-hot-loader/babel"
 ]
Was this page helpful?
0 / 5 - 0 ratings

Related issues

niba picture niba  路  4Comments

mtscout6 picture mtscout6  路  3Comments

mqklin picture mqklin  路  3Comments

rockchalkwushock picture rockchalkwushock  路  3Comments

mattkrick picture mattkrick  路  3Comments