React/react router/heroku question here (it is probably heroku where it is failing).
I am following this wonderful tutorial: https://medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d#.y77yjte2j and everything works up to the point where I post it to heroku and I try to navigate to https://appname.herokuapp.com/about and I get a 404 Not Found/nginx error. Of course, per the tutorial it is supposed to display an About page.
Bottomline: React router is not working on heroku and I can't figure out why.
I have tried modifying my server/app.js
file as suggested in this: React routes are not working in facebook's create-react-app build
// server/app.js const express = require('express'); const morgan = require('morgan'); const path = require('path'); const app = express(); console.log('hi from /src/server.js') // Setup logger app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms')); // Serve static assets app.use(express.static(path.resolve(__dirname, '..', 'build'))); // Always return the main index.html, so react-router render the route in the client app.get('/about', (req, res) => { console.log('hi from app.get.about') console.log(req) console.log(res) res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html')); }); app.get('/*', (req, res) => { console.log('hi from app.get') console.log(req) console.log(res) res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html')); }); module.exports = app;
but it doesnt work nor does it log anything at all in the console:
2017-01-20T21:03:47.438140+00:00 heroku[web.1]: Starting process with command `bin/boot` 2017-01-20T21:03:49.540005+00:00 app[web.1]: Injecting runtime env into /app/build/static/js/main.242e967b.js (from .profile.d/inject_react_app_env.sh) 2017-01-20T21:03:49.695317+00:00 app[web.1]: Starting log redirection... 2017-01-20T21:03:49.695899+00:00 app[web.1]: Starting nginx... 2017-01-20T21:03:51.108255+00:00 heroku[web.1]: State changed from starting to up 2017-01-20T21:04:22.720627+00:00 heroku[router]: at=info method=GET path="/" host=sentieoapp1.herokuapp.com request_id=fb8bc13b-f6b5-47bc-8330-443f28e211df fwd="132.147.73.97" dyno=web.1 connect=0ms service=3ms status=200 bytes=627 2017-01-20T21:04:22.746761+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:22 +0000] "GET / HTTP/1.1" 200 386 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36" 2017-01-20T21:04:23.076521+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:23 +0000] "GET /static/js/main.242e967b.js HTTP/1.1" 200 62263 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36" 2017-01-20T21:04:23.056416+00:00 heroku[router]: at=info method=GET path="/static/js/main.242e967b.js" host=sentieoapp1.herokuapp.com request_id=436d5ce5-ee39-4ab7-9e12-f5871e0fd552 fwd="132.147.73.97" dyno=web.1 connect=0ms service=25ms status=200 bytes=62540 2017-01-20T21:04:23.745285+00:00 heroku[router]: at=info method=GET path="/static/css/main.9a0fe4f1.css" host=sentieoapp1.herokuapp.com request_id=80438aaa-58c4-456e-8df9-7a29e49bc4ba fwd="132.147.73.97" dyno=web.1 connect=0ms service=2ms status=200 bytes=560 2017-01-20T21:04:23.766676+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:23 +0000] "GET /static/css/main.9a0fe4f1.css HTTP/1.1" 200 301 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36" 2017-01-20T21:04:24.044940+00:00 heroku[router]: at=info method=GET path="/static/media/logo.5d5d9eef.svg" host=sentieoapp1.herokuapp.com request_id=bcbc1906-3b90-4f13-a700-f432f79c725d fwd="132.147.73.97" dyno=web.1 connect=0ms service=1ms status=200 bytes=2902 2017-01-20T21:04:24.065013+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:24 +0000] "GET /static/media/logo.5d5d9eef.svg HTTP/1.1" 200 2671 "https://sentieoapp1.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36" 2017-01-20T21:04:26.264631+00:00 heroku[router]: at=info method=GET path="/about" host=sentieoapp1.herokuapp.com request_id=0caef324-9268-4ebb-a3f5-0fb047100893 fwd="132.147.73.97" dyno=web.1 connect=0ms service=4ms status=404 bytes=403 2017-01-20T21:04:26.284717+00:00 app[web.1]: 10.158.165.5 - - [20/Jan/2017:21:04:26 +0000] "GET /about HTTP/1.1" 404 191 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"
and this is where I'm stuck. I am familiar with Express and have gotten it to work on heroku before but this is a whole nother level of nightmare. I understand that this is not server side routing but rather react doing routing from within a single index.html page. But if I can get it to work on my local machine why does it not work on Heroku?
React Router works locally but not on Heroku #98.
To deploy React app on Heroku, we need to add buildpacks. Click on the Settings tab and then click on Add buildpack button inside the Buildpacks section. Our React buildpack URL is https://github.com/mars/create-react-app-buildpack. Copy this URL and add it to buildpack like below.
Connected React Router is a Redux binding for React Router v4 and v5. It synchronizes router state with Redux store via a unidirectional flow and uses react-hot-loader to facilitate hot reloading of functional components while preserving state.
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.
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 -MultiViews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ 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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With