'React Router not working correctly on production with express backend
I have Single page application built with React and Express as backend.
There are only two pages/main components: the application(<SinglePage/ >) and Not found page(<PageNotFound / >).
I want to display the application when "/" url is requested and to display the Not Found when any other url is requested(for example /home, /test, /insertInvalidUrlHere etc.).
This logic works perfectly on Localhost, but when I deploy the app to the domain, the single page view is displayed correctly(on url '/'), but when any other url is requested the attached page below is displayed, not the Not found page as expected. I also found out that the Not found page is displayed only if index.html is appended to the URL(domain.com/index.html).
I already tried these:
- placing <Navigate to"/404"/> at the end and changing the route path to "/404".
- changing the route path to "" or entirely removing it.
- using HashRouter
- deleting the app and deploying it again and again from the start.
None of these worked.
I also tried to build the app locally, and then use http-serve ( npm i -g http-serve ) to serve the build folder. Everything is displayed correctly in this case.
Could you please advise me, what I am doing wrong and what should be amended in order for the logic to work correctly when I deploy the app to the domain.
Frontend: App.tsx
import { BrowserRouter as Router , Route, Routes} from "react-router-dom";
import PageNotFound from "./Components/PageNotFound/PageNotFound";
import SinglePage from "./SinglePage";
function App() {
return (
<>
<Router>
<Routes>
<Route path="/" element={<SinglePage />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</Router>
</>
);
}
export default App;
Backend: App.ts
const express = require("express");
const nodemailer = require("nodemailer");
const cors = require("cors");
const request = require("request");
var https = require('https');
var fs = require('fs');
const app = express();
app.use(express.json());
app.use(cors());
let transporter = nodemailer.createTransport({
host: "mail.mail.com",
port: 465,
secure: true,
auth: {
user: "[email protected]",
pass: "TestPassword123",
}
});
transporter.verify((err, success) => {
err
? console.log(err)
: console.log(`Server is ready to receive messages: ${success}`);
});
app.post("/send", function (req, res) {
let mailOptions = {
from: `${req.body.mailerState.email}`,
to: "[email protected]",
subject: `Message from: ${req.body.mailerState.email}`,
text: `${req.body.mailerState.message}`,
};
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
res.json({
status: "fail",
});
} else {
console.log("Message Sent");
res.json({
status: "success",
});
}
});
});
const port = 3001;
https
.createServer(
{
key: fs.readFileSync("key.pem"),
cert: fs.readFileSync("cert.pem"),
},
app
)
.listen(port, () => {
console.log("Server is running at port 3001");
});
app.get('/', (req, res) => {
res.send("Hello from express server.")
})
Solution 1:[1]
I assume the error is locating in your router - since you have path="/" first, all subsequent urls ("/home","/test","/error/404", etc) will hit this path. try to use exact so your routing looks like this:
<Routes>
<Route path="/" exact element={<SinglePage />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Schiellerup |

