Hiber
Hiber

Reputation: 141

React router doesn't work on express server

I am new to react, and I am trying to build a chat-app with it. I used react-router to load different components according to the url. In my react project foler (client/src/index.js), the code is as follows:

import {BrowserRouter as Router, Route} from 'react-router-dom';    
...
ReactDOM.render(
  <Router>
    <div>
      <Route exact path='/' component={App} />
      <Route path='/customer' component={CustomerPage} />
      <Route path='/support/:support_id' component={SupportPage} />
    </div>
  </Router>,
  document.getElementById('root')
);
...

It works find when I start it in the react folder with "npm start". But when I run "npm run build" and serve the static files with express server, it can only serve the App page in the '/' path, while for '/customer' and '/support/:support_id" path, it loads nothing.

In the express server folder, I load the static files in the following way:

server/app.js:

...
var indexRouter = require('./routes/index');
app.use('/static', express.static(path.join(__dirname, '../client/build//static')));
app.use('/', indexRouter);
...

server/routes/index.js:

...
router.get('/', function(req, res) {
  res.sendFile('index.html', {root: path.join(__dirname, '../../client/build/')});
});
...

Any help will be appreciated!

Upvotes: 14

Views: 17587

Answers (6)

robinhoody78
robinhoody78

Reputation: 1

I finally found the full solution to serve a React Router App on Express server. Here's the code:

Front End Side

  1. Be sure that your router looks like the code below

router.tsx

import { createBrowserRouter } from "react-router-dom";
import routes from "./routes";

export const appRouter = createBrowserRouter(routes, { basename: "/" });

  1. Build your React project:

    npm run build OR yarn build

Back End Side

  1. Create an express app

app.ts

import express, { Application } from "express";
import path from "path";

const app: Application = express();

// Rest of your code if needed (CORS,api,etc...)

const root = path.join(__dirname, "build");
app.use(express.static(root));

app.use("/*", (req, res) => {
  res.sendFile(path.join(__dirname, "build", "index.html"));
});
export default app;

server.ts

require("dotenv").config();
import http from "http";
import app from "./app";
const server = http.createServer(app);

server.listen(process.env.PORT, async () => {
  console.log(`HTTP Express server listening on port: ` + process.env.PORT);
});


  1. move react app build to the root of your express server

root:

  • build > static, index.html,...
  • app.ts
  • server.ts
  1. run your server babel-node server.ts, go to http://yoururl, it works !

Upvotes: 0

Fernando Francis
Fernando Francis

Reputation: 3

app.get("/get/data/from/store", (req, res) => {
             your sql codes here
  });

// You must place all your above REST API Calls before the below codes. // Otherwise all urls '*' will be forwarded to index.html

// wildcard handles any requests that don't match the ones ABOVE

app.use(express.static(path.join(__dirname, '/build')))

    app.get('*', (req, res) => {
      res.sendFile(path.resolve(__dirname+'/build/','index.html'));
    });
    app.listen(port, () => {
      console.log("Server running on port ", port);
    });
    
    put the wildcard app.get('* call at the end. Just before the app.listen.

Upvotes: 0

Premo89
Premo89

Reputation: 54

Getting rid of this block helped me

app.use(function(req, res, next) {
  next(createError(404));
});

Upvotes: 0

You must serve the static files and handle any request in your index.js:

const express = require('express');
const path = require('path');

const app = express();

// Serve the static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));

// Handles any requests that don't match the ones above
app.get('*', (req,res) =>{
    res.sendFile(path.join(__dirname+'/client/build/index.html'));
});

const port = process.env.PORT || 5000;
app.listen(port);

console.log('App is listening on port ' + port);

Upvotes: 1

Sarang Kartikey
Sarang Kartikey

Reputation: 111

* worked instead of using / in app.get() otherwise it'll always show cannot get. Thanks @basse

Upvotes: 0

Tholle
Tholle

Reputation: 112787

React Router does all the routing in the browser, so you need to make sure that you send the index.html file to your users for every route.

This should be all you need:

app.use('/static', express.static(path.join(__dirname, '../client/build//static')));
app.get('*', function(req, res) {
  res.sendFile('index.html', {root: path.join(__dirname, '../../client/build/')});
});

Upvotes: 55

Related Questions