React Router works on Heroku for my MERN app as long as I load index.html before anything else. Client-side routing fails if I go directly to a route in the address bar (e.g., mysite.com/products). However, clicking on a link to the products page from the home page works.
This problem has been discussed extensively for many years, but I can't solve the issue in my environment. Strategies have evolved, and it's not clear what the best situation is at the present date.
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.3.0",
"react-scripts": "^5.0.0"
My project structure is:
root
backend
: Express serverfrontend
: React App
I tried adding a static.json
file to the project root.
{
"root": "build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
I also tried handling the routing fallback in Express. After all my routes, I have:
const __dirname = path.resolve()
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '/frontend/build')))
} else {
app.get('/', (req, res) => {
res.send('API is running...')
})
}
// error handling middleware
// define error-handling middleware last, after other app.use() and routes calls
app.use(notFound) // 404 errors
app.use(errorHandler) // other errors
// for all non-api requests, return index.html from the build directory
app.get('*'),
(req, res) => {
res.sendFile(path.resolve(__dirname, 'frontend', 'build', 'index.html'))
}
// server listener
const PORT = process.env.PORT || 6060
app.listen(PORT, () =>
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
)
I'd be grateful for the insight into what I missed.
CodePudding user response:
To solve:
- Put error-handling middleware last.
- Set a static path to the build directory
- Directing all non-API routes to
index.html
No static.json
was required. Also, make sure process.env.NODE_ENV
is set to production
in Heroku config vars.
const __dirname = path.resolve()
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '/frontend/build')))
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, 'frontend', 'build', 'index.html'))
)
} else {
app.get('/', (req, res) => {
res.send('API is running....')
})
}
// error handling middleware
// define error-handling middleware last, after other app.use() and routes calls
app.use(notFound) // 404 errors
app.use(errorHandler) // other errors
// server listener
const PORT = process.env.PORT || 6060
app.listen(PORT, () =>
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
)