17

I have a React app with navigation powered by react-router that I run in development with webpack-dev-server and the history fallback option enabled. Here is the routes I have defined in my index.js

ReactDOM.render((
  <Router history={browserHistory}>
    <Route path="/" component={App}>
      <IndexRedirect to="/intro" />
      <Route path="/intro" component={Intro} />
      <Route path="/device" component={Device} />
      <Route path="/clothing" component={Clothing} />
      <Route path="/build" component={Build}>
        <IndexRedirect to="/build/pattern" />
        <Route path="/build/pattern" component={Pattern} />
        <Route path="/build/layout" component={Layout} />
        <Route path="/build/color" component={Color} />
      </Route>
      <Route path="/capture" component={Capture} />
      <Route path="/review" component={Review} />
    </Route>
  </Router>
), document.getElementById('app'))

When I navigate through links, everything works fine and I can see the nested route components nesting within their parent route components as expected. For example when I navigate to /build/color I can see my App component nesting the Build component nesting the Color component.

Where it fails is when I try to hit the refresh button within the nested route. React entirely fails to load and I get the following error

GET http://localhost:8080/build/app.js 404 (Not Found)

There is indeed not such a file in my app but I am still confused as of why it is automatically looking for this file instead of reloading the route from the root. Note that hitting refresh on pages like /device does work without an issue.

Let me know if you need more details about my setup. Thanks!


Solution:

My webpack setup is actually using HtmlWebpackPlugin which was injecting the path to my app bundle as follows

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

All I needed to do was to configure my webpack public path as publicPath: '/' so that the bundle would be injected as follows

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

Ucodia
  • 7,410
  • 11
  • 47
  • 81

4 Answers4

39

It doesn't work because it can't load your javascript bundle. I'm guessing that the problem is with your path in script tag in HTML. Probably you have specified the path to app.js with dot at the beginning like this one <script src="./app.js"></script>, if this is true please remove dot and check if the problem still exists <script src="/app.js"></script>

Let's illustrate what is the difference between ./app.js and /app.js

Case 1. You are loading page using first level of routes like / or /intro

  • ./app.js: HTML tries to load script from http://address/app.js
  • /app.js: HTML tries to load script from http://address/app.js

No difference

Case 2. You are loading page using second level of routes /build/pattern

  • ./app.js: HTML tries to load script from http://address/build/app.js - doesn't exist
  • /app.js: HTML tries to load script from http://address/app.js - OK
niba
  • 2,821
  • 1
  • 19
  • 23
  • 1
    My webpack setup currently injects my app bundle as `` which yields a result similar to `./app.js` in my case. I just need to configure webpack to inject the absolute path to my bundle. If you also have the solution for that I would take it too :) – Ucodia Oct 17 '16 at 01:17
  • 13
    If you are using `HTML Webpack Plugin` to generate HTML you need to set `webpackConfig.output.publicPath = '/'` – niba Oct 17 '16 at 06:34
  • This answer helped me find a solution to a similar issue with Express serving a React front end though index.html. I had to remove the `"homepage": "."` from my package.json files. – Carter Cobb Dec 20 '20 at 03:06
  • I had the same problem with React Router 6 and Vite. In my case I had to do the opposite, i.e to *add* the dot (and slash) in front of the path to my entrypoint: `` – daniero Jan 04 '23 at 12:57
  • I didn't have a dot or a slash: ``. Changing to `src="/main.jsx"` fixed this problem for me. Thanks @niba for pointing me in the right direction! I was hopelessly looking at Vite config and how my routes were set up... – evces Mar 01 '23 at 19:44
14

@niba's answer perfectly solved my problem. I have been having the problem that when I nest a <Route/> element inside a component that is already being rendered by a <Route/>, it will fail to load the script bundle.js when I try to go to a sub-route url. After adding the following in the webpackConfig.json, everything is back to normal.

module.exports = {
    ...
    output: {
        path: path.resolve('dist'),
        publicPath: '/',
        filename: 'bundle.js'
    },
    ...
}
Z_K
  • 151
  • 1
  • 5
3

In package.json file, just set

    "homepage": "/"
2

For those who have tried the above and stil have issues, I'm using html-webpack-plugin on my webpack configuration, so it injects the bundle inside the HTML with no need to add any script import on index.html

So I removed the following line from my index.html file:

<script src="/bundle.js"></script>

And added the following configuration on webpack plugins section:

// some other imports 
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
...
webpack default config
...

plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      hash: true,
      inject: true,
    }),
    ...
    other plugins,
  ],

}

Just remember to also use the output configuration accordingly to your project, such as mine:

output: {
    path: path.resolve(__dirname, 'public'),
    publicPath: '/',
    filename: 'bundle.js',
  },
Gustavo Garcia
  • 521
  • 5
  • 5