Home > other >  React Router on Heroku
React Router on Heroku

Time:01-03

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 server
    • frontend: 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:

  1. Put error-handling middleware last.
  2. Set a static path to the build directory
  3. 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
  )
)
  • Related