React-hot-loader: HMR does not work if navigated to nested path in React Router v4

Created on 10 Aug 2017  路  12Comments  路  Source: gaearon/react-hot-loader

Description

<Switch>
    <Router exact path="/one" component={One} />
    <Router path="/one/two" component={OneTwo} />
    <Router path="/or/whatever" component={WhatEver} />
</Switch>

With above route config If i navigate to nested path (ie. /one/two, /or/whatever) and make changes to the code entire browser reloads instead of HMR. But HMR works smoothly on non nested paths (ie. /one). If I change the depth of nested paths for example path="/one/two" to path="/blah" then HMR works as expected.

Expected behavior

Should Hot Reload also in nested path like /one/two , /or/whatever not only in /one

Actual behavior

When I am navigated to path /one in browser and edit some component hot reloading just works fine.
BUT
When I an navigated to path /one/two HMR does not work, entire browser reloads

In above Steps to reproduce example if i change /one/two to be only one level depth say /blah then it works.

Environment

  • Webpack 2
  • React Router v4

React Hot Loader version: ^3.0.0-beta.7

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

  1. node -v: 8.0.0
  2. npm -v: 5.3.0

Then, specify:

  1. Operating system: Ubuntu 16.04 LTS
  2. Browser and version: Google Chrome 60

Reproducible Demo

<Switch>
    <Router exact path="/one" component={One} />
    <Router path="/one/two" component={OneTwo} />
    <Router path="/or/whatever" component={WhatEver} />
</Switch>

Now navigate to /one/two or /or/whatever route in browser and then make chages to the code entire browser reloads instead of just HMR.

Most helpful comment

After hours of hair pulling struggle :) I finally figured out the actual issue and it is not directly related to either Webpack or React Hot Loader or React Router or any other library at least for now at least for me. When using HTML5 push state to manipulate browsers history WE MUST PROVIDE <base> tag in our html head section. After providing <base href="/" /> to the head section of my html, HMR works like a charm even in nested routes. Yay!!!

<!DOCTYPE html>
<html>
    <head>
        <base href="/" /> <!-- THIS TINY LITTLE THING -->
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="root"></div>
        <script src="/main.bundle.js"></script>
    </body>
</html>

All 12 comments

Related to Webpack's HMR, not React-Hot-Loader.
Sometimes you have to accept HMR in more than one place. Check console logs to understand how change bubbles to the top and where you have to accept the change

After hours of hair pulling struggle :) I finally figured out the actual issue and it is not directly related to either Webpack or React Hot Loader or React Router or any other library at least for now at least for me. When using HTML5 push state to manipulate browsers history WE MUST PROVIDE <base> tag in our html head section. After providing <base href="/" /> to the head section of my html, HMR works like a charm even in nested routes. Yay!!!

<!DOCTYPE html>
<html>
    <head>
        <base href="/" /> <!-- THIS TINY LITTLE THING -->
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="root"></div>
        <script src="/main.bundle.js"></script>
    </body>
</html>

@lekhnath I had same issue. Your solution greatly works well!! Thank you.

@lekhnath didn't work for me and even if it did, I need an explanation for why this would be needed, what's going on!?

@leidegre Sorry, I've no idea why it worked. That's why even the issue is resolved I've not closed this.

@lekhnath if you have a complete example I could look at, I could probably help. I've been through this a couple of times, most recently I've been working with code splitting and I think it's necessary to just keep these things separate for everything to under different circumstances.

I close it. Code splitting is a real problem with HMR but this issue was resolved.

@lekhnath Confirming this solution worked for me. Thanks for saving me hours of debugging!

This solution works because typically you have your main script imported like this:

<script type="text/javascript" src="main.js"></script></body>

Well, basically Webpack handles writing this to HTML.

And if you try to navigate to some deeply nested routes, such as https://yoursite.tld/one/two without <base href="/"> in your <head> this big main.js script is tried to be imported from https://yoursite.tld/one/two/main.js and in fact it is in https://yoursite.tld/main.js.

In fact, you can mitigate this issue even without <base> tag, if you manage to import your script this way:

<script type="text/javascript" src="/main.js"></script></body>

Note the leading slash before main.js.

Same Issue With:

webpack 4.8.3
react router dom 4.2.2

I had the same Issue, but @lekhnath solution would flash the correct page and then load the default homepage instead. However adding "publicPath:'/'" to my Webpack module.exports output solved the issue perfectly for me. Now all of my deep links and params work as expected.

The Router

<BrowserRouter>
      <Switch>
          <Route path="/password_resets/:resetToken" render={props =>
               <PasswordReset {...this.props} />
                    }/> 
      </Switch>
</BrowserRouter>
 ```
**The Solution publicPath: '/' in webpack.config.js:**

module.exports = {
output: {
path: path.resolve('web'),
filename: 'js/bundle.js',
publicPath: '/'
},...

**Also use historyApiFallback: true**

devServer: {
historyApiFallback: true
},...
```

I am Facing similar issue with my website also, I have tried the solution provided by @lekhnath to put the base url as <base href="/">, it actually solved my issue for localhost but its still giving issue with my real website.

I have also tried Solution suggested by @pdgehrke to put

devServer: {
   historyApiFallback: true
}

and

module.exports = {
    output: {
        path: path.resolve('web'),
        filename: 'js/bundle.js',
        publicPath: '/'
    }

But its still not solving my issue, can anyone suggest where i am going wrong or you can help me out with this.

Thanks

After hours of hair pulling struggle :) I finally figured out the actual issue and it is not directly related to either Webpack or React Hot Loader or React Router or any other library at least for now at least for me. When using HTML5 push state to manipulate browsers history WE MUST PROVIDE <base> tag in our html head section. After providing <base href="/" /> to the head section of my html, HMR works like a charm even in nested routes. Yay!!!

<!DOCTYPE html>
<html>
    <head>
        <base href="/" /> <!-- THIS TINY LITTLE THING -->
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="root"></div>
        <script src="/main.bundle.js"></script>
    </body>
</html>

God bless you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

theKashey picture theKashey  路  4Comments

Anahkiasen picture Anahkiasen  路  5Comments

rockchalkwushock picture rockchalkwushock  路  3Comments

mattkrick picture mattkrick  路  3Comments

reintroducing picture reintroducing  路  4Comments