React-hot-loader: React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work.

Created on 11 Apr 2019  ·  58Comments  ·  Source: gaearon/react-hot-loader

What is the actionable thing to do here? I've followed the required steps to set it up, but still see this warning.

Most helpful comment

Sure.

// App.jsx

import { hot } from 'react-hot-loader/root'

// ...

export default hot(App)
// .babelrc

{
  "plugins": ["react-hot-loader/babel"]
  // ...
}
// package.json

{
  "dependencies": {
    "react-hot-loader": "^4.8.3",
    "@hot-loader/react-dom": "^16.8.6"
    // ...
  }
  // ...
}
// webpack.config.js

{
  // ...
  resolve: {
    alias: {
      'react-dom': '@hot-loader/react-dom'
    }
  }
}

All 58 comments

you need to add the matched version for react-hot-dom in your package file

"@hot-loader/react-dom": "^16.8.6",

and in your webpack config, you need to add

 alias: { 'react-dom': '@hot-loader/react-dom'  }

Okay, that indeed resolves the issue. But shouldn't that be added as a step 4? The readme is confusing about this. It says a Webpack plugin is required, then recommends using the Babel plugin instead. The Webpack plugin apparently patches React DOM for you to basically turn it into @hot-loader/react-dom, but it is unclear if it can be used in conjunction with the Babel plugin. Can both plugins be used at the same time or will that lead to conflicts or other downsides?

Using the Webpack plugin in conjunction with the Babel plugin does not remove the warning. Solely using the Webpack plugin doesn't either. Only the Babel plugin combined with @hot-loader/react-dom and a Webpack config alias does.

For me, just using the webpack plugin (with include: /node_modules/ so it only runs on node_modules(?) -- maybe you're missing this part?) and the babel plugin together seems to make everything work correctly, including making that warning go away.

I'm also really confused by the readme. I'm slightly worried that I might have things set up incorrectly and only working by coincidence and that it might break on an update.

I probably forgot include: /node_modules/ for the Webpack plugin. Will try that.

Usually, it's not about include, but exclude.
There are 3 ways to set up "hot-patch", and webpack-loader is working only for webpack, while it's not the only one bundler one could use.

PS: Feel free to change README to be more clear and understandable.

The Webpack plugin with include: /node_modules/ indeed does the trick. @hot-loader/react-dom and the Webpack config is alias is no longer required in that case.

@theKashey is it okay to use the Babel and Webpack plugins at the same time? Or are they meant to be used separately?

That's ok, they are taught to be friends :)
They were not before webpack-loader got ability to patch react-dom and probably some pieces of that _past_ are still among readme.

@rybon would you kindly share the config with us?

Sure.

// App.jsx

import { hot } from 'react-hot-loader/root'

// ...

export default hot(App)
// .babelrc

{
  "plugins": ["react-hot-loader/babel"]
  // ...
}
// package.json

{
  "dependencies": {
    "react-hot-loader": "^4.8.3",
    "@hot-loader/react-dom": "^16.8.6"
    // ...
  }
  // ...
}
// webpack.config.js

{
  // ...
  resolve: {
    alias: {
      'react-dom': '@hot-loader/react-dom'
    }
  }
}

Alternative:

// App.jsx

import { hot } from 'react-hot-loader/root'

// ...

export default hot(App)
// package.json

{
  "dependencies": {
    "react-hot-loader": "^4.8.3"
    // ...
  }
  // ...
}
// webpack.config.js

{
  // ...
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        include: /src/
      },
      {
        test: /\.(js|jsx)$/,
        use: 'react-hot-loader/webpack',
        include: /node_modules/
      }
      // ...
  ]
}

Notice:

  • no .babelrc change required
  • no @hot-loader/react-dom required
  • no Webpack config resolve.alias required

Now the question is, which configuration is preferable? What are the downsides of the alternative configuration? That is not clear to me. Personally, I prefer the alternative configuration, because it requires less configuration. But if it does not work as properly as the Babel approach, I'd rather use that.
When using the Webpack approach, should the .babelrc plugin be used as well? Or can it safely be omitted?

@rybon I agree with you it's quite confusing for me as well and the first approach doesn't work as expected because of react-dom alias. and the babel approach working perfectly fine for me.

btw you can use babel-config.js instead of .babelrc if you are using babel 7

Okay. I just noticed when using the Webpack approach without @hot-loader/react-dom that in some cases the HMR only works the first time, but not in subsequent times. Adding the .babelrc / babel-config.js plugin back in resolves that issue.

So, I guess the recommendation would be to always use the Babel plugin? And then decide to go with either the Webpack plugin or the @hot-loader/react-dom and the Webpack resolve.alias setting.

You have to use babel-plugin or webpack-loader to make RHL work. @hot-loader/react-dom in any form - is just an addition.

How would you set this up using Parcel?
Because I have the babel-plugin but still see this warning.

Hello,
a get this message

"React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work" when using https://parceljs.org/ bundler. Can this message be fixed for https://parceljs.org/ ?

This is how I tried to load App (using Hooks):

import { hot } from 'react-hot-loader'
import React from 'react'
...
export default hot(module)(App)

is there any working example using Parcel + React Hooks ?

Best Regards,
Krešimir

For parcel use hot-loader/react-dom

Use alias field in package.json to rewire your project. This will affect dev and production modes. See https://github.com/parcel-bundler/parcel/pull/850
{
"alias": {
"react-dom": "@hot-loader/react-dom"
}
}

Hello @theKashey ,
now it is fine. No WARN message shown.

how I start the web app:
NODE_ENV=development parcel -p 3500 assets/index.html --open

package.json snippet:
...
"alias": {
"react-dom": "@hot-loader/react-dom"
},
....

Hi, I suffer from the same warning as other. I do not use _webpack_, I work on a electron app which utilizes the electron-compile.

If I use __yarn__ (yarn add react-dom@npm:@hot-loader/react-dom) I do net get the warning, but it adds

"react-dom": "npm:@hot-loader/react-dom",

to my __package.json__ which is something __npm__ is not compatible with.

npm ERR! code EUNSUPPORTEDPROTOCOL npm ERR! Unsupported URL Type "npm:": npm:@hot-loader/react-do

I would like to stick with __npm__ instead of __yarn__, but I am not able to get rid of the warning with my setup:

"dependencies": {
    "@hot-loader/react-dom": "^16.8.6",
    "electron-compile": "^6.4.4",
    "electron-devtools-installer": "^2.1.0",
    "electron-squirrel-startup": "^1.0.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-hot-loader": "^v4.8.4"
  },
  "devDependencies": {
    "babel-plugin-transform-async-to-generator": "^6.24.1",
    "babel-plugin-transform-es2015-classes": "^6.24.1",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "electron-forge": "^5.2.4",
    "electron-prebuilt-compile": "4.0.0",
    "eslint": "^3",
    "eslint-config-airbnb": "^15",
    "eslint-plugin-import": "^2",
    "eslint-plugin-jsx-a11y": "^5",
    "eslint-plugin-react": "^7"
  },
  "alias": {
    "react-dom": "@hot-loader/react-dom"
  }

It says, that __.compilerc__ (the electron-compile config) also accepts environments with the same syntax as __.babelrc__. My __.compilerc__ looks like:

{
  "env": {
    "development": {
      "application/javascript": {
        "presets": [
          ["env", { "targets": { "electron": "1.6.0" } }],
          "react"
        ],
        "plugins": ["transform-async-to-generator", "transform-es2015-classes", "react-hot-loader/babel"],
        "sourceMaps": "inline"
      }
    },
    "production": {
      "application/javascript": {
        "presets": [
          ["env", { "targets": { "electron": "1.6.0" } }],
          "react"
        ],
        "plugins": ["transform-async-to-generator", "transform-es2015-classes"],
        "sourceMaps": "none"
      }
    }
  }
}

I tried to add the es2017-node7 babel, preset, but still no luck.

I also tried to use __babel-plugin-module-resolver__ and changed the _development_ section of my __.compilerc__ to:

...
"plugins": ["transform-async-to-generator", "transform-es2015-classes", "react-hot-loader/babel",
        ["module-resolver", {
              "alias": {
                 "react-dom": "@hot-loader/react-dom"
              }
            }]
        ],
...

Still no luck 😢

Is there a way to get __react-hot-reload__ to work without needing to use __yarn__ ?

You can always “ln” real directories.

You can always “ln” real directories.

Thank you, I tried this already and it works. But this approach makes a local development setup quite difficult. 🤕

The issue with __react-🔥-dom__ not being used properly is caused by __babel-plugin-module-resolver__ and the fact _babel_ is ignoring _node_modules_ by default.

The __electron-compile__ project is marked as deprecated by now, so there won't be probably any support for setting aliases for npm modules in the future.

I tried a different approach with setting an __environment variable__ in the script for the local development and using the right ReactDOM respectively:

import 'react-hot-loader';
import React from 'react';
import ReactDOM from 'react-dom';
import PatchedReactDOM from '@hot-loader/react-dom';
import App from './components/App';

if (process.env.REACT_DOM === 'patched') {
  PatchedReactDOM.render(<App />, document.getElementById('App'));
} else {
  ReactDOM.render(<App />, document.getElementById('App'));
}

but although the if-else is being resolved properly, I still get the warning.

Not, it would not work _exactly_ this way - by default RHL would _patch_ something names react-dom. You might patch another thing, calling ReactHotLoader.patch(React, PatchedReactDOM); manually, but it would not remove the message.

Probably the best option is to move this message from _configure_ time to a _render_ time(AppContainer constructor), giving you options to suppress or _fix_ it.

v4.8.5 gives two options:

  1. ReactHotLoader.patch(React, PatchedReactDOM);, error shall not be displayed
  2. setConfig({showReactDomPatchNotification: false}), error would not be displayed.

Hello Anton,

sorry for bothering you again, but I am more confused than ever. I do not want to __hide__ the warning but set-up my configuration right.

I updated __react-hot-loader__ to __4.8.5__. My current entry point file looks like:

import ReactHotLoader from 'react-hot-loader';
import PatchedReactDOM from '@hot-loader/react-dom';
import ReactDOM from 'react-dom';
import React from 'react';
import App from './Front-End/App';

ReactHotLoader.patch(React, PatchedReactDOM);
ReactDOM.render(<App />, document.getElementById('App'));

The warning message about react-🔥-dom patch is gone, but in the terminal I can see:
__React-Hot-Loader: Hot Module Replacement is not enabled__

This is electron App, so I also tried the "old" pattern:

import ReactHotLoader, { AppContainer } from 'react-hot-loader';
import PatchedReactDOM from '@hot-loader/react-dom';
import ReactDOM from 'react-dom';
import React from 'react';
import App from './Front-End/App';

ReactHotLoader.patch(React, PatchedReactDOM);

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

render();
if (module.hot) {
  module.hot.accept(render);
}

but I still get the __React-Hot-Loader: Hot Module Replacement is not enabled__ message in the terminal.

Also, _eslint_ complains about ReactHotLoader import: __Default export is not declared in imported module__

React-Hot-Loader: Hot Module Replacement is not enabled

(!module.hot) {console.error('React-Hot-Loader: Hot Module Replacement is not enabled');
So module.hot is not defined - It's hard to guess why.


ReactHotLoader.patch(React, PatchedReactDOM); ReactDOM.render(<App />, document.getElementById('App'));

__THIS IS WRONG CODE__. The idea is to USE another version of react-dom.

ReactHotLoader.patch(React, PatchedReactDOM);
PatchedReactDOM.render(<App />, document.getElementById('App'));

Also, eslint complains about ReactHotLoader import: Default export is not declared in imported module

The question - how it might know it.

After reading through this entire thread, and the readme several times I'm no clearer on the recommended way to set this up.

Readme is super confusing and there is so much conflicting information scattered throughout this repository.

@mrfelton - could you elaborate a bit more. There is always some room for improvement and I am keen to hear was is not clear and what is the problem you are solving.

Hi, sure. So on the surface my issue is as per the title of this issue. I see the error :"React-Hot-Loader: Hot Module Replacement is not enabled" in my logs (even though HMR does seem to be working).

But the deeper issue is that the recommended config as detailed at the top of the readme does not work. The only way I have been able to get things to work is by cobbling together a config that is based on various suggestions by frustrated users on github, parts of the readme that are not listed as part of the recommended setup, and pure trial and error.

I don't know if I have things set up correctly. Based on the readme and the error in my console would indicate that I don't, yet HMR does work.

There are several different elements to setting up the configuration and I don't really understand which ones are needed and which are not, and more specifically why one is needed over the other, the relationship between them and what they actually do.

My app is an electron app and it's using webpack.

Here are the key parts of my setup (if you want to look at the actual config or try it for yourself, the project is https://github.com/LN-Zap/zap-desktop/tree/next):

package.js

  "dependencies": {
    "@hot-loader/react-dom": "16.8.6",
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-hot-loader": "4.8.8",
}

index.js

import React from 'react'
import ReactDOM from 'react-dom'

const render = Component => {
  ReactDOM.render(
    <Provider store={store}>
      <Component history={history} />
    </Provider>,
    MOUNT_NODE
  )
}

render(Root)

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

Root.js

import { hot } from 'react-hot-loader/root'

export default hot(connect(
  mapStateToProps,
  mapDispatchToProps
)(Root))

babel.config.js

  plugins: [
    'react-hot-loader/babel',
    ...,
  ],

webpack.config.js

  resolve: {
    alias: {
      'react-dom': '@hot-loader/react-dom',
    },
  },
  devServer: {
    hot: true
  }

This config emits this error twice in my console:

webpack-internal:///./node_modules/react-hot-loader/index.js:7 React-Hot-Loader: Hot Module Replacement is not enabled

if I remove 'react-hot-loader/babel from the babel config file then I only see the error once and HMR still works.

Your documentation does not mention needing to add devServer: { hot: true } in the webpack config but if I remove this I can not get HMR to work at all regardless of what combination of the other config options I use.

Adding import 'react-hot-loader' at the top of index.js changes nothing.

Removing if (module.hot) { ... from the bottom of index.js breaks HMR yet this is not part of the recommended config.

Changing export default hot(connect(mapStateToProps, mapDispatchToProps)(Root)) to export default connect(mapStateToProps, mapDispatchToProps)(hot(Root)) makes no difference

So what I can conclude is that in my setup at least, the recommended config does not work and in order to get a setup that does work (but that emits this error message stating that HMR is not loaded) I have to add additional config that is not mentioned in your documentation.

as per the title of this issue. I see the error :"React-Hot-Loader: Hot Module Replacement is not enabled"

Look like you are talking about another issue

even though HMR does seem to be working

But according to the https://github.com/gaearon/react-hot-loader/blob/master/index.js#L10 - React-Hot-Loader is not.

__Place a breakpoint here__, and double check what's inside module variable. Why hot does exists for index.js, but not for react-hot-loader.

My app is an electron app and it's using webpack.

That's important difference. Electron has it's own "runtime".

module.hot.accept('./containers/Root', () => {

Then don't use react-hot-loader/root - they are doing the same

import { hot } from 'react-hot-loader/root'

Then don't use module.hot.accept - they are doing the same

Your documentation does not mention needing to add devServer: { hot: true } in the webpack config

Each setup has it's own way to properly setup HMR, and that's not quite our business. For "webpack" applications it's just --hot for webpack-dev-server, while for a custom webpack configurations it could be something very complicated.

For "webpack" applications it's just --hot for webpack-dev-server

What do you mean by this? Are you saying that if we are using webpack-dev-server (which we are) then the only thing we need to do is to add --hot and we can remove all of the other config??

Usually that's all you need. No need of HotModuleReplacementPlugin, no need of additional settings - just ask webpack to be hot. Check almost any examples in our examples folder.

module.hot.accept('./containers/Root', () => {
... Then don't use react-hot-loader/root - they are doing the same

Ok, understood. After removing the usage of react-hot-loader/root and using only module.hot.accept it still works

import { hot } from 'react-hot-loader/root'
...Then don't use module.hot.accept - they are doing the same

Ok, understood. But in this case if I only use react-hot-loader/root without module.hot.accept it does not work.

Check almost any examples in our examples folder.

I can't see any example where the only config is to set --hot.

https://github.com/gaearon/react-hot-loader/blob/master/examples/styled-components/package.json#L6 -> "start": "NODE_ENV=development webpack-dev-server --hot",

But in this case if I only use react-hot-loader/root without module.hot.accept it does not work.

That's strange. It should not be that way.

I can't see any example where the only config is to set --hot.
... -> "start": "NODE_ENV=development webpack-dev-server --hot",

Right, but --hot is not the only config!

I asked:

What do you mean by this? Are you saying that if we are using webpack-dev-server (which we are) then the only thing we need to do is to add --hot and we can remove all of the other config??

To which you replied

Usually that's all you need. No need of HotModuleReplacementPlugin, no need of additional settings - just ask webpack to be hot. Check almost any examples in our examples folder.

But in that example you pointed to you also have webpack config, you have babel config, you are wrapping the root component with hot()

... --hot is far from the only config!

Please distinguish HMR, which is provided by the bundler, and RHL which is separate. You need:

  • HMR is __properly__ enabled
  • better to have a babel plugin
  • webpack plugin is optional, and may _partially_ replace a babel plugin
  • react-🔥-dom is required for hooks and might be _delivered_ via webpack-plugin or hot-loader/react-dom.

Your issue is about "HMR is __NOT__ properly enabled", which makes everything else senseless.

That helps a lot, thanks.

So as I understand it now HMR is responsible for making module.hot available and in my case at the time when RHL initialises it is not set for some reason hence why I get the error message. However by the time it gets to index.js module.hot is now set which is why I can get RHL working by manually setting it up using module.hot.accept

.... No. If you are seeing that message - then RHL picked a __production__ version, which does nothing.
But - I just remember you said something about seeing TWO messages - could you double check - it shall be only one message, as long as a module could be executed only once, and it might be __two RHLs__ present in your system.

Just double check messages origin.

There are 2 messages, both read "React-Hot-Loader: Hot Module Replacement is not enabled"

1) from webpack-internal:///./node_modules/react-hot-loader/index.js
2) from webpack://renderer/./node_modules/react-hot-loader/index.js?

Here are the startup logs from the console (I added a little debugging into both your index.js file and into my index.js file):

image

That's sounds more like two Electron threads - so might be legit, but why then module.hot in RHL index.js was displayed only once?

Warning: Could not replay rendering after an error. This is likely a bug in React. Please file an issue.
Uncaught TypeError: Cannot set property 'getCurrentStack' of undefined

@yzw7489757 - that's not very helpful.

@theKashey
When I do this

// webpack.config.dev.js
alias:{
    'react-dom':'@hot-loader/react-dom'
}

Writing like this will result in an error, and commenting will warn,react-🔥-dom patch is not detected. React 16.6+ features may not work.

// App.js
import React from 'react';
import ReactDOM from 'react-dom'; //---
import './index.css';
import zhCN from 'antd/es/locale-provider/zh_CN';
import { LocaleProvider } from 'antd';
import moment from 'moment';
import App from '@/views/App'; // App as hot(App)
import 'moment/locale/zh-cn';

moment.locale('zh-cn');
ReactDOM.render(
  <LocaleProvider locale={zhCN}>
    <App />
  </LocaleProvider>,
  document.getElementById('root')
);

````
The following error was thrown
``` js
Warning: Could not replay rendering after an error. This is likely a bug in React. Please file an issue.
Uncaught TypeError: Cannot set property 'getCurrentStack' of undefined

``` json
// package.json
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"@hot-loader/react-dom":"^16.8.6",
"autodll-webpack-plugin": "^0.4.2",
"babel-eslint": "^10.0.2",
"babel-loader": "^8.0.6",
"babel-plugin-import": "^1.12.0",
"cache-loader": "^4.1.0",
"css-loader": "^3.1.0",
"react-hot-loader": "^4.12.9"
},
"dependencies": {
"antd": "^3.20.5",
"axios": "^0.19.0",
"connected-react-router": "^6.5.2",
"immutable": "^4.0.0-rc.12",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^7.1.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-transition-group": "^4.2.1",
"redux": "^4.0.4"
}
}

``` js
//.babelrc
{
  "presets": ["@babel/env", "@babel/react"],
  "plugins": ["react-hot-loader/babel","@babel/plugin-proposal-class-properties"]
}

Chrome Version 75.0.3770.142 (Official Build) (64-bit)
Mac Version 10.14.5 (18F132)

What should I do?

Plase, create a separate issue with an example or a detailed stack trace. This is not the bug with React or React-Hot-Loader - I think this is dependency resolution level problem - react-dom could not read a variable react, like https://github.com/facebook/react/issues/13991

@mrfelton

Hello all, I had this same error "React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work. #1227"

I took @mrfelton 's advice and I got rid of the error in the console, however the hot-module reloading is still not working. As was suggested I modified my webpack.dev-client.config file.

The hot module re-loading seems to work for my html sometimes however it absolutely does not work for my css.

When I save my css file it detects there is a change and the console status is
`

[HMR] bundle rebuilding
client.js:242 [HMR] bundle rebuilt in 80ms
process-update.js:41 [HMR] Checking for updates on the server...
process-update.js:112 [HMR] Nothing hot updated.
process-update.js:121 [HMR] App is up to date.
`

My app is a react app and it's using webpack.

Below are the key parts of my setup and if you want to try it your self please do It would be greatly appreciated as I have been stuck on this for some time and it is agonizing;
In Terminal:

  1. git clone https://github.com/JapinderSandhu/noenglish_website/tree/ssr-dynamic-imports
  2. npm install
  3. npm run dev OR npm run prod

package.json

  "dependencies": {
    "@hot-loader/react-dom": "16.8.6",
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-hot-loader": "4.8.8",
}

app.js

import React from "react"
import ReactDOM from "react-dom"
import AppRoot from "./components/AppRoot"
import { AppContainer } from "react-hot-loader"

function render(Component) {
 ReactDOM.hydrate(
   <AppContainer>
     <Component />
   </AppContainer>,
   document.getElementById("react-root")
 )
}
render(AppRoot)

if (module.hot) {
 module.hot.accept("./components/AppRoot.js", () => {
   const NewAppRoot = require("./components/AppRoot.js").default
   render(NewAppRoot)
 })
}

.babelrc

  {
"presets": [
   [
     "env",
     {
       "targets": {
         "browsers": ["last 2 versions"]
       },
       "debug": false
     }
   ],
   "babel-preset-react"
 ],
 "plugins": ["syntax-dynamic-import", "universal-import"],
 "env": {
   "development": {
     "plugins": ["react-hot-loader/babel"]
   }
 }
}

webpack.dev-client.js

const path = require("path")
const webpack = require("webpack")
const ExtractCssChunks = require("extract-css-chunks-webpack-plugin")

module.exports = {
name: "client",
 mode: "development",
 entry: {
   vendor: ["react", "react-dom"],
   main: [
     "react-hot-loader/patch",
     "babel-runtime/regenerator",
     "webpack-hot-middleware/client?reload=true",
     "./src/main.js"
   ]
 },
 resolve: {
   alias: {
     'react-dom': '@hot-loader/react-dom'
   }
 },
 output: {
   filename: "[name]-bundle.js",
   chunkFilename: "[name].js",
   path: path.resolve(__dirname, "../dist"),
   publicPath: "/"
 },
 devServer: {
   contentBase: "dist",
   overlay: true,
   hot: true,
   stats: {
     colors: true
   }
 },
 optimization: {
   runtimeChunk: {
     name: "bootstrap"
   },
   splitChunks: {
     chunks: "initial",
     cacheGroups: {
       vendors: {
         test: /[\\/]node_modules[\\/]/,
         name: "vendor"
       }
     }
   }
 },
 devtool: "source-map",
 module: {
   rules: [
     {
       test: /\.js$/,
       exclude: /node_modules/,
       use: [
         {
           loader: "babel-loader"
         }
       ]
     },
     {
       test: /\.css$/,
       use: [
         { loader: ExtractCssChunks.loader },
         {
           loader: "css-loader"
         }
       ]
     },
     {
       test: /\.(jpg|png|gif)$/,
       use: [
         {
           loader: "file-loader",
           options: {
             name: "assets/page1_media/images/[name].[ext]"
           }
         }
       ]
     },
     {
       test: /\.md$/,
       use: [
         {
           loader: "markdown-with-front-matter-loader"
         }
       ]
     }
   ]
 },
 plugins: [
   new ExtractCssChunks({ hot: true }),
   new webpack.DefinePlugin({
     "process.env": {
       NODE_ENV: JSON.stringify("development"),
       WEBPACK: true
     }
   }),
   new webpack.HotModuleReplacementPlugin()
 ]
}

I can confirm @rybon's https://github.com/gaearon/react-hot-loader/issues/1227#issuecomment-482518698 is _working_ 🔥 - and the easiest to implement.

In case it helps anyone, here's how this looks like for Rails Webpacker:

// package.json

{
  "dependencies": {
    "react-hot-loader": "^4.8.3"
    // ...
  }
  // ...
}
# config/webpacker.yml

# ...
  dev_server:
    https: false
    host: localhost
    port: 3035
    public: localhost:3035
    hmr: true
    # Inline should be set to true if using HMR
    inline: true
    overlay: true
    compress: true
    disable_host_check: true
    use_local_ip: false
    quiet: false
    headers:
      'Access-Control-Allow-Origin': '*'
    watch_options:
      ignored: '**/node_modules/**'
    client_log_level: trace

# ...
// config/webpack/environment.js

const { environment } = require('@rails/webpacker')
// ..
const reactHotReload = {
  test: /\.(js|jsx)$/,
  use: 'react-hot-loader/webpack',
  include: /node_modules/,
}
environment.loaders.insert('reactHotReload', reactHotReload, { after: 'babel'})

module.exports = environment

and then the following pattern in your code (Note: to keep state with redux & Co, don't apply this to top level App but to lower level components (containers, pages etc)):

import { hot } from 'react-hot-loader/root'
import React from 'react'
// ...
export default hot(MyComponent)

As @rybon says, no need for @hot-loader/react-dom and webpack alias ReactDOM patching setup.

Doesn't work If I'm using webpack externals.

// webpack.config.js
...
externals: {
  'react-dom': 'ReactDOM'
}
...

Don't use them in a dev mode. That's the only advice I could give you, sorry.

I tried removing the externals, tried config webpack loader as @rybon said, tried following the guide from README. none work like expect.
it works in a weird way. the hot reload always one step behind.
I change the code from A to B, it doesn't work, the content still is A in the browser. change the code again, from B to C, the content changed to B in the browser.

Try update RHL to the latest 4.12.14 version (leased early this week) - it shall address this problem.

Just in case you arrive here while using neutrinojs, here's my webpack.config.js file:

const neutrino = require('neutrino');
const webpack = require('webpack');
const dotenv = require('dotenv');

const env = dotenv.config().parsed;

const envKeys = Object.keys(env).reduce((prev, next) => {
  prev[`process.env.${next}`] = JSON.stringify(env[next]);
  return prev;
}, {});

const config = neutrino().webpack();

const pluginConfig = {
  plugins: [
    ...config.plugins,
    new webpack.DefinePlugin(envKeys)
  ]
};

const aliasConfig = {
  resolve: {
    ...config.resolve,
    alias: {
      ...config.resolve.alias,
      'react-dom': '@hot-loader/react-dom'
    }
  }
};

if (process.env.ENVIRONMENT !== 'production') {
  module.exports = {
    ...config,
    ...pluginConfig,
    ...aliasConfig
  };
} else {
  module.exports = {
    ...config,
    ...pluginConfig
  };
}

Based on all previous discussion it seemed pretty straight forward to just inject the alias into neutrino's config.

Hope someone finds this to be useful :rocket:

@lili21 I guess it's a feature belongs to webpack, maybe webpack externals have higher priority than an alias. So u can revise your webpack.config.js as below:

webpack.base.js

externals: {
  react: 'React',
  'react-router-dom': 'ReactRouterDOM'
}

webpack.development.js

resolve: {
  alias: { 'react-dom': '@hot-loader/react-dom' }
}

webpack.production.js

externals: {
  'react-dom': 'ReactDOM'
}

Doesn't work If I'm using webpack externals.

// webpack.config.js
...
externals: {
  'react-dom': 'ReactDOM'
}
...

I have the same problems

More or less expected. However, why do you need it as external in dev mode?

Soooo like literally the docs resolved this issue for anyone still running into the console warning:

yarn add react-dom@npm:@hot-loader/react-dom

installs the hot-loader patch and links it for use without having to eject anything. so win-win :)

Thanks React Team

I have got the same issue and tried to resolve it according to these guide here, but got same error message.
Pls reach me out and help me.
Thank you.

It Worked For Expo Web App.
File webpack.config.js

const createExpoWebpackConfigAsync = require('@expo/webpack-config');

module.exports = async function (env, argv) {
  const config = await createExpoWebpackConfigAsync(env, argv);
  // Customize the config before returning it.
  config.resolve.alias['react-dom'] = '@hot-loader/react-dom';
  return config;
};
Was this page helpful?
0 / 5 - 0 ratings

Related issues

tiberiumaxim picture tiberiumaxim  ·  4Comments

jljorgenson18 picture jljorgenson18  ·  3Comments

esturcke picture esturcke  ·  3Comments

Anahkiasen picture Anahkiasen  ·  5Comments

reintroducing picture reintroducing  ·  4Comments