React Routing works in local machine but not Heroku
I actually came across this post first before 3 hours of searching through react-router and heroku documentation. For swyx, and anyone else having the same problem, I'll outline the minimum of what you need to do to get this working.
router.js - (Obviously change AppSplash and AppDemo to your components)
export default <Router history={hashHistory}> <Route path="/" component={App}> <IndexRoute component={AppSplash}/> <Route path="demo" component={AppDemo}/> </Route></Router>
app.js
import React, { Component } from 'react'class App extends Component {static propTypes = { children: PropTypes.node}render() { const { children } = this.props return ( <div> {children} </div> )}}export default App
Create a new file in the root of your home directory and name it static.json. Put this into it.
{ "root": "build/", "clean_urls": false, "routes": { "/**": "index.html" }}
Push to heroku again. The routes should work this time.
Explanation:
You need to modify Heroku's default webpack, otherwise the service gets confused with how to handle the client-side routing. Essentially what static.json does. The rest is just the correct way to handle the routing according to the 'react-router' documentation.
How to fix client-side routing errors (Heroku 404 errors):
React Browser Router
If you're using React Browser Router, as an npm module with create-react-app, then the solution (which works for me) is to create a static.json
file (within the same directory as package.json
).
{ "root": "build/", "clean_urls": false, "routes": { "/**": "index.html" }}
Here is why this solution works:
Create-react-app is for the most part a Node.Js server which serves client-side React. The public
static directory is mapped to the /
endpoint, and visiting this endpoint from a browser will download the index.html
webpage. This webpage in turn loads the React components. And because React Browser Router is a React component, the routes are loaded dynamically after visiting the /
endpoint. In other words, before the index.html
webpage is loaded all our React Browser Router routes will result in 404 errors on Heroku. To resolve this issue, a static.json
file can be used to map any endpoints with the following pattern /**
to the index.html
file, which in turn will load React Browser Router and correctly load the react components for that route.
From an Apache HTTP server:
Likewise, on an Apache HTTP server creating an .htaccess
file in the public
directory, will remap all endpoints that match /**
to the index.html
file.
Options -MultiViewsRewriteEngine OnRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^ index.html [QSA,L]
More resources
Also read the "Deployment" section of the create-react-app
README, which has a ton of good information on how to reconfigure the server to use client-side routing.
https://facebook.github.io/create-react-app/docs/deployment
React Static Router
Lastly, React Router offers a static router, React Static Router, which can be used with the "react-dom/server" npm module on a Node.js server, to render JSX server-side, and doesn't need static.json
or .htaccess
reconfiguration.
Try this:
app.get("*", (req, res) => { let url = path.join(__dirname, '../client/build', 'index.html'); if (!url.startsWith('/app/')) // since we're on local windows url = url.substring(1); res.sendFile(url);});
Worked for me when I put into server.js.