So basically my issue is that I’ve mostly only made APIs using node/express/mongoose and have never served my react apps since someone else always did that for me in our Plesk (I think through Apache.)
Now that I’m finally doing some MERN stack stuff for a client on the side I was wondering what the ‘correct’ way of serving a React App that has already been built.
Express and React-Router clash. BY that I mean that if I have an ‘About’ page and I go to example.com/about
how does express know that’s a page on my single-page React app? There’s only a index.html anything else dealing with routes on my page are handled by react-router.
But what if it is a file or a folder? So this has been my solution for being able to serve both the website’s files and still being able to access the website’s routes:
const apps = { //websites are put in this object and iterated through to make the code below less bloated.
example: {
folder: "example-website",
app: express(),
server: null,
port: 80,
protocol: "http",
cert: null,
subdomains: []
}
}
for(let website of Object.keys(apps)){ //Itterate through every website.
website = apps[website]; //Make the website key the website object instead.
const websitePath = path.join(__dirname+`/client/${website.folder}/build`); //Save path to website's build folder for ease of use.
fs.readdir(websitePath, (err, files) => { //itterate through all files in the build folder
if(err){ //log errors.
console.log(err)
} else { //continue if there wasn't an error.
const fileArray = files.filter(file => file !== 'index.html')//remove 'index.html' from the array.
website.app.use('/*', (req,res) =>{
let route = req.params["0"].substring(0, req.params["0"].indexOf('/')); //take the first part of the route.
if(fileArray.includes(route)){ //check if the first part of the route matches a file or folder.
res.sendFile(path.join(__dirname+`/client/${website.folder}/build/${req.params["0"]}`));
} else { //If the list of files doesn't include the route than the route is probably a route within the React App in React-Router
res.sendFile(path.join(__dirname+`/client/${website.folder}/build/index.html`));
}
});
//...more irrelevant code here.
}
})
}
I was wondering if this was the correct way to deal with the conflict between my single-page React app’s use of react-router and the way Express handles routes.
2
Answers
I am not really sure that maybe you were confused about the API,
I will explain that out maybe you can better understand about MERN,
First there is 2 kind : 1 is backend(API) 2 is Frontend (in this case is Reactjs),
so backend and front end, each has its own business, i am sure you knew that , so
Once the UI(Frontend in this case is Reactjs ) need data they will call api by fetch(basicly) call to the backend(API in this case is Nodejs) and get that data out .
=> so you know how Frontend and backend work , next :
Reactjs they divide many element to a component to load
See : in the top right there is a header it is a component , a input is another component and the other is another component.
It run : when you search something, the header and the input is not load , the other component is load , so when url change , the react-router will help you catch url you define in router you can read more here about react-router .
==> It mean , when go to different url , they only trigger the component that url use
localhost:3000/ to localhost:3000/about
If you can elaborate more on the issue, it’ll be much more helpful for others to explain.
Building Back-end is like a “building ways where you can make a request(send CRUD operations from client to database through server) and get a response (fetch data and deliver to a client)” by so-called ‘API calls’. Of course, you can manipulate data in the back-end, etc., but that’s pretty much what it does.
So, hypothetically let’ say your back-end folder has Express.js because Express sets up routes by
app.use
, and most probably you know what it means. (*Routes in Express.js(back-end) is different than Routes in React – for instance, if the backend Route is a road between your app and a database, the Route in React is like roads between your app and a client)Front-End is like a shop where you bring the data(goods) that are fetched from the database(your warehouse) and present it nicely to a client(to sell).
Now, you need to make API calls in your FRONT-END via back-end routes using Axios or fetch(), etc.. BECAUSE “the way(routes) to the server is established in your back-end folder”. There will be 2 parts running in your computer(in DEVELOPMENT phase), one is server(back-end) and the other is your webpage(front-end). If a client navigate to a particular route, and the component will be called, and the component has methods (directly or indirectly) and makes API calls, and do something with the data.
I’ll leave a link to my recent work of full-stack React app, you may go and check the structure to get some ideas.
Check out my repo and structure here