11

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!

Hiber
  • 111
  • 1
  • 1
  • 5

6 Answers6

55

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/')});
});
Tholle
  • 108,070
  • 19
  • 198
  • 189
  • 8
    This is the only correct answer out of dozens related to this very same problem. Others disregard the `static` folder resulting in `index.html` being served instead of css, chunks, etc. @Hiber please accept this as the answer. – basse Nov 25 '18 at 09:28
  • As @basse said I encountered this problem in Node.js + Koa + React and solved with this answer. – M_YK Jan 05 '20 at 17:34
  • It is hard to combine when we wanna combine Express and React Router into same project. From my opinion, be careful to put star like above, because it could be effected to your server's URLs. It is better if we defind client URLs by specificed name like /home /dasdboard /login /logout ...etc – Thịnh Kều Jan 24 '20 at 04:40
  • 1
    With this solution I seem to still be having the issue that `index.html` is being served instead of css and chunkfiles, but only from secondary subroutes (i.e. `host:port/route` works, but `host:port/route/subroute` does not - the page is blank and all css and js assets are just the html file again, being served from `host:port/route/static//filename..). Any ideas why that's happening? – Seth Lutske Apr 21 '21 at 19:40
  • I just get a blank page with the head and root but nothing inside. What's going on? – LUKER Mar 31 '22 at 22:24
1

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);
0

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

Yunnosch
  • 26,130
  • 9
  • 42
  • 54
Sarang Kartikey
  • 101
  • 2
  • 8
  • This is not enough additional information to merit making an answer. It is practically only a "Thanks." which is not a valuable contribution to the collection of Q/A pairs StackOverflow strives to be. Please either [edit] to increase usefulness of this answer, or turn it into a comment (once you collected enough reputation https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead ) – Yunnosch Jul 14 '19 at 06:49
0

Getting rid of this block helped me

app.use(function(req, res, next) {
  next(createError(404));
});
Premo89
  • 56
  • 3
0
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.
0

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 !