29

I thought I was starting to understand React Router, but I hit a new wall when adding a library that loads css for its components. Everything works fine when a navigate from my home, to the page containing the component, but when I refresh it, the urls of the fonts are broken...

I found some pointer here and here but no luck so far. Is this a common issue ? How to work around it ?

I use webpack dev server with default config built by a yeoman scaffolder.

The library I use is React Fa to display icons.

When I load my app on http://localhost:8000/ everything displays fine, then I navigate to http://localhost:8000/customer/ABCD1234/chat and my icons are ok. The font was loaded properly.

Then I refresh the page, and I see in the console :

DOMLazyTree.js?019b:56 GET http://localhost:8000/customer/ABCD1234/assets/926c93d201fe51c8f351e858468980c3.woff2

Which is obviously broken because the customer part shouldnt be here...

Here is my router so far :

ReactDOM.render(
  <Router history={browserHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Index}/>
      <Route path='customer/:id'        component={Customer}    />
      <Route path='customer/:id/chat'   component={CustomerChat}/>
      <Route path="*"                   component={ NotFound }  />
    </Route>
  </Router>
, document.getElementById('support-app'));

I also tried adding a <base href="/"/> to my index.html, but I get a nice warning in red in the console, so maybe not the best idea :

Warning: Automatically setting basename using is deprecated and will be removed in the next major release. The semantics of are subtly different from basename. Please pass the basename explicitly in the options to createHistory

Community
  • 1
  • 1
Sephy
  • 50,022
  • 30
  • 123
  • 131

4 Answers4

30

It sounds like you have defined relative paths to your assets and icons in your CSS.

background-image: url('assets/image/myicon.png')

instead, try an absolute path:

background-image: url('/assets/image/myicon.png')

As React apps are single page applications, and you enter your app on /, all urls are going to work fine no matter the page you navigate to, since they are relative to the root where you started.

But as soon as you reload your page on a different path such as /customer/ABCD all your assets are going to be relative to that, hence the wrong url you see in your console.

Also, if using webpack, you can try to set your publicPath in your config file like this:

...
output: {
    path: 'assets',
    publicPath: '/'
},
...
hampusohlsson
  • 10,109
  • 5
  • 33
  • 50
  • In theory, I think that would work, but the asset in question is a font, loaded by font awesome as I mentionned. And I cant change the path, unless I build font awesome from SCSS on my own, but I loose the advantages of CDN... Here is the CSS : https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css – Sephy May 09 '16 at 08:26
  • How would you deal with multiple differents sources of static assets. Because I think my issue might come from something like that. As fontawsome are loaded with a relative path but my pictures come from an absolute asset path, just like you mention... – Sephy May 12 '16 at 16:52
  • Are you using plain CSS in your project or SASS? If the latter, I'd rather include font-awesome in my project and redefine the base path, than having to manage multiple assets paths: http://fontawesome.io/get-started/ – hampusohlsson May 16 '16 at 15:21
8

I hava a same problem.

  1. Add a <base href="http://whatever"> tag to the head of a page containing react-router's HTML using the default browserHistory

  2. Load the page - history.js will output 2 errors, Warning: Automatically setting basename using <base href> is deprecated and will be removed in the next major release. The semantics of are subtly different from basename. Please pass the basename explicitly in the options to createHistory

  3. Change the react-router history to use history where history is const history = useRouterHistory(createHistory)({ basename: 'http://whatever' }), which should fix the problem (as basename is now explicitly passed)

  4. Reload the page

https://github.com/reactjs/react-router/issues/3387

5/9 update

In my case.

index.html

<head>
  <base href="/" />
  <script src="app.js"></script>
</head>
<body>
  <div id="app">
  </div>
</body>

app.js

import { Router , useRouterHistory } from 'react-router'
import { createHistory } from 'history'

const browserHistory = useRouterHistory(createHistory)({ basename: '/' })

render(
  <Router routes={routes} history={browserHistory}/>,
  document.getElementById("app")
);

And then reload the warning to disappears. hope this is useful.

RoyLiou
  • 81
  • 3
  • As I mentionned in my question, I have already tried that, I did find this github issue. For the sake of being sure, I tried it again by copy pasting your code, I get the warning even if I did step 3 of your explanation... – Sephy May 09 '16 at 09:36
3

I solved this thanks to react-script:2+

You just have to create a js file called setupProxy.js, it will be loaded by the developement server. Now you have complete control over your proxy:

const proxy = require('http-proxy-middleware');

module.exports = function(app) {
    console.log("configuring development proxies to point to localhost:4000")
    app.use(proxy('/api', { target: 'http://localhost:4000/' }));
    app.use(proxy('/graphql', { target: 'http://localhost:4000/' }));
};

https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#configuring-the-proxy-manually

Edit: The old link broke, this is an updated one: https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually

Zied Hamdi
  • 2,400
  • 1
  • 25
  • 40
0

I solved this by loading font awesome cdn on the app index page. Then it is available on all routes in all situations.

KyleM
  • 618
  • 5
  • 17