So, you are here after browsing through half of the internet searching about configuring react router or SPA in general for your production and could not get the actual idea on why its not working or what's the concept ?
Well! You are in the right place, sit tight, this is not just another react router configuration tutorial. We will explain what you dont find over the internet: The actual concepts of routing along with production ready configuration on three most famous servers: Apache HTTP Server, Nginx and Tomcat.
Why two routings required ? Why is this confusion ? Why cant we have only one ? Since SPA is client side application, why not only Client side routing works ? So many questions asked. Enough!!, Here are the answers,
See the below image, it shows how the routing works in Server side and Client side. As you can see, in a multi page application, a java web application for instance, the server refers to a configuration file. This configuration file could be a simple web.xml or if you are using a framework like Spring, it could be a applicationContext.xml file. No matter what framework you use or what configuration file you use, all it has is the routing information.
When a user clicks on a link to navigate to another page, the routing information is looked up in the configuration file. Then server returns the target page and the user sees the new html page. Since server is taking care of the routing its called Server side routing.
Now compare this to the single page application. In this case, there is only a single page,
index.html
. The webserver always returns index.html
for any routing. This is because all the code is in a single page. This is why all the SPA frameworks has their own routing frameworks. In react, its the react-router framework.Such a client side routing works fine in development environment. But how can you make sure it works on a production server ? Since the production servers are created before SPA frameworks came in to usage, we need special instructions for them to work with newer frameworks. That means we need a combination of Server Side and Client Side Routings.
This is why when you directly push your code to production, you will see
404 Not Found
error when you refresh. This is because when you refresh on a page with URL "/user", the server tries to find that route which will not be there in server configuration The basic gist of all this conversation is this very concept of combination of Server Side Routing and Client Side Routing. When you try to route to a page say "/user", the server tries to find that page. We need to fool the server by always directing it to index.html
. Once we are inside index.html
, our client side routing in SPA will take care of the rest.See below for the production ready configurations that does exactly what is explained above.
Remember!
404 Not Found
errors if Server Side Routing is missing or misconfiguredindex.html
irrespective of routeWe have configured react router on Create React App (CRA) scaffolding application. Let us see how to make it run on all three servers. Dont worry we have included the working application at the end. Check "Download Source" section.
We are configuring server side configuration here, If you want to setup client side routing painlessly, head over to this easy to understand step by step tutorial - Create React App - React Router Setup
There is enough information on what are the differences between HashRouter and BrowserRouter so we are not going to see the differences. However, we want you to understand which is used when and how they work. Think of HashRouter as a development environment routing. Although it can work on production, it appends a
#
in the URL which would not feel like production URLs.HashRouter uses history library and anchor blocks, also called as html bookmarks. This is the reason you dont need any server side configuration to make it working. But hold on, are you ok to have your URLs appended with an ugly
#
. Imagine you also have html bookmarks or anchor blocks in your pages. Then the URLs looks more uglier.This is where the BrowserRouter comes in. Although it requires server side routing to be setup for them to work properly. This is why we used BrowserRouter, to make your routing production ready.
For your reference this is how our URLs would look like if HashRouter is used:
http://localhost:8080/react-routing-config/#/dashboard
http://localhost:8080/react-routing-config/#/user
Not so pretty right !! Read on..
Remember!
#
characters to the URLs which does not look pretty on a production environment.1. httpd.conf - default context location (/htdocs) :
Remember!
LoadModule rewrite_module modules/mod_rewrite.so
module for the configurations to workloading...
2. httpd.conf - custom context location (say, /react-routing-config) :
This one is a bit tricky one, we need to tell your build tool to build with the context name and use that build instead. Also, we need to create a Virtual Host and add configuration using <Directory> tag. Here are the steps:a. Add
a. Add basename
as your context name in BrowserRouter tag
loading...
b. Add homepage
in package.json
loading...
c. Finally, the httpd.conf
configuration
loading...
3. .htaccess file
loading...
The -f, -d and -l flags represents file, directory and a symbolic link respectively. The configuration says that when you receive a request from index.html do nothing as its already in index.html, next follows the non index.html requests like "/user". In this case, we check if the request is not a file, directory or symbolic link, if so just direct them to index.html.
Now, navigate to the dashboard screen and user screen and make sure you are not getting 404 errors when you refresh.
1. nginx.conf - default context location (/html) :
This configuration is pretty simple. All we have to do is add
try_files
loading...
2. nginx.conf - custom context location (say, /react-routing-config) :
Build the application with the context name and add the required configuration on server. Here are the steps:a. Add
a. Add basename
as your context name in BrowserRouter tag
loading...
b. Add homepage
in package.json
loading...
c. Finally, the nginx.conf
configuration
loading...
Tomcat configuration is a bit different than other two servers. Since Tomcat only serves a web application, we need to modify our application structure to look like the structure of a Java Web Application.
Using <error-page>
in web.xml :
Create
WEB-INF
folder and create a web.xml
file as below and proceed with the configurations. The idea is to redirect always to index.html when 404 error occurs.loading...
Using rewrite.config
and Valve
:
If for some reason you dont want to use error-page, there is another approach using
rewrite.config
file. It uses a tomcat feature called Valve
. First remove the error-page tag from web.xml and Simply create a file as below and name it as rewrite.config
. Place this file in WEB-INF
folder.loading...
In the tomcat
server.xml
, add the below config and proceed with the configurations.loading...
1. Default context location (/ROOT) :
This configuration is pretty simple. All we have to do is copy the application to the
ROOT
folder.2. Custom context location (say, /react-routing-config) :
Build the application with the context name and deploy the application to Tomcat. Here are the steps:a. Add
a. Add basename
as your context name in BrowserRouter tag
loading...
b. Add homepage
in package.json
loading...
c. Finally, deploy the application to react-routing-config directory in webapps
Thats all folks !! Happy coding. If you feel this helped you, keep supporting us by or or below or on the articles on social media.