Deploy React JS in Tomcat:-

Deploy react JS in tomcat or any servlet container is a challenge and bit tricky. There is an issue in one of my app that I am developing. I have used Browser Router in my app.

So the issue is there were no errors as such in the code but nothing is loading.I see a White Screen with no errors. I checked the console and saw its throwing 404 for some of my bundled static resources.

A strange behavior is noticed, if I run the app in web pack dev server same code works fine and routers works fine as well.But same behavior is not observed once I deploy to tomcat.

So after a lot of research and thinking, i got the solution. As you know BrowserRouter uses HTML5 history API to keep your UI in sync with URL.So, For example, if you used React Router with a route for, /todos/42 the webpack development server will respond properly localhost:3000/todos/42 , but a production build as above will not.Check out this link to understand the problem. React router takes the root URL by default, hence able to serve static resources from tomcat ROOT directory.But Once you deploy the build files to a different path is not able to serve static content.

In this article, we will see how we can configure our code and deploy in tomcat successfully.We will use Maven to create a war of our UI and deploy in tomcat. Deploy React JS in Tomcat needs some changes in router property .

Tools Used:-

Maven 3.3.9

Npm

Pom.xml:-

< project xmlns = " http://maven.apache.org/POM/4.0.0 " xmlns: xsi = " http://www.w3.org/2001/XMLSchema-instance " xsi: schemaLocation = " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd " > < modelVersion > 4.0.0 </ modelVersion > < groupId > com.frugalis </ groupId > < artifactId > Frugalis </ artifactId > < version > 0.0.1-SNAPSHOT </ version > < packaging > war </ packaging > < properties > < project.build.sourceEncoding > UTF-8 </ project.build.sourceEncoding > < npm.output.directory > build </ npm.output.directory > </ properties > < build > < finalName > ${project.artifactId} </ finalName > < plugins > < plugin > < groupId > org.apache.maven.plugins </ groupId > < artifactId > maven-war-plugin </ artifactId > < version > 2.1.1 </ version > < configuration > < webResources > < resource > < directory > ${npm.output.directory} </ directory > </ resource > </ webResources > < webXml > ${basedir}/web.xml </ webXml > </ configuration > </ plugin > < plugin > < groupId > org.codehaus.mojo </ groupId > < artifactId > exec-maven-plugin </ artifactId > < version > 1.3.2 </ version > < executions > < execution > < id > npm run build (compile) </ id > < goals > < goal > exec </ goal > </ goals > < phase > compile </ phase > < configuration > < executable > npm </ executable > < arguments > < argument > run </ argument > < argument > build </ argument > </ arguments > </ configuration > </ execution > </ executions > < configuration > < environmentVariables > < CI > false </ CI > < NPM\_CONFIG\_PREFIX > ${basedir}/npm </ NPM\_CONFIG\_PREFIX > < NPM\_CONFIG\_CACHE > ${NPM\_CONFIG\_PREFIX}/cache </ NPM\_CONFIG\_CACHE > < NPM\_CONFIG\_TMP > ${project.build.directory}/npmtmp </ NPM\_CONFIG\_TMP > </ environmentVariables > </ configuration > </ plugin > </ plugins > </ build > < profiles > < profile > < id > local </ id > < activation > < activeByDefault > true </ activeByDefault > </ activation > < build > < plugins > < plugin > < groupId > org.codehaus.mojo </ groupId > < artifactId > exec-maven-plugin </ artifactId > < configuration > < environmentVariables > < PUBLIC\_URL > http://localhost:8080/${project.artifactId} </ PUBLIC\_URL > < REACT\_APP\_ROUTER\_BASE > /${project.artifactId} </ REACT\_APP\_ROUTER\_BASE > </ environmentVariables > </ configuration > </ plugin > </ plugins > </ build > </ profile > < profile > < id > prod </ id > < build > < plugins > < plugin > < groupId > org.codehaus.mojo </ groupId > < artifactId > exec-maven-plugin </ artifactId > < configuration > < environmentVariables > < PUBLIC\_URL > http://frugalisminds.com/${project.artifactId} </ PUBLIC\_URL > < REACT\_APP\_ROUTER\_BASE > /${project.artifactId} </ REACT\_APP\_ROUTER\_BASE > </ environmentVariables > </ configuration > </ plugin > </ plugins > </ build > </ profile > </ profiles > </ project >

Web.xml:-

< web-app xmlns = " http://java.sun.com/xml/ns/j2ee " xmlns: xsi = " http://www.w3.org/2001/XMLSchema-instance " xsi: schemaLocation = " http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app\_2\_4.xsd " version = " 2.4 " > < display-name > frugalis </ display-name > < error-page > < error-code > 404 </ error-code > < location > /index.html </ location > </ error-page > </ web-app >

We Configure BrowserRouter in our app as follows, provide full path of your context as follows. Above code redirects all errors to index.html. < BrowserRouterbasename={process.env.REACT_APP_ROUTER_BASE||''}> App.jsx:-

import React , { Component } from 'react' ; import { BrowserRouter , Link , Route , Switch } from 'react-router-dom' ; import Home from './Home.jsx' ; import ContactUs from './ContactUs.jsx' ; import Blog from './Blog.jsx' ; class App extends Component { render ( ) { return ( < div className = " App " > < div className = " App-header " > < h2 > Welcome to React </ h2 > </ div > < BrowserRouter basename = { process . env . REACT \_APP\_ROUTER\_BASE || '' } > < div > < ul className = " nav " > < li > < Link to = " / " > Home </ Link > </ li > < li > < Link to = " /blog " > Blog </ Link > </ li > < li > < Link to = " /contactUs " > Contact Us </ Link > </ li > </ ul > < Switch > < Route path = " /blog " component = { Blog } /> < Route path = " /contactUs " component = { ContactUs } /> < Route path = " / " component = { Home } /> </ Switch > </ div > </ BrowserRouter > </ div > ) ; } } export default App ;

We declared three routes in our sample app, Our maven script will replace the basename with actual tomcat url context. process.env.REACT_APP_ROUTER_BASE will be replaced by maven .

Basically, when you type the URL by hand, by default the server will look for a file with that path, stored on its disk — if not found, it will show a 404 error. What you want to do is internally redirect the request for static resources to the index of your application.

Now we run

npm install

mvn clean install

OutPut:-

Note:- For a simple application built using create-react-app if we can to configure and Deploy React JS in Tomcat. We need to configure a relative path which can be done from your package.json. by declaring home page as follows.let's say we have an app folder inside web app in tomcat known as sampleapp. We want to have our deployed app in that location. So the relative path configuration would be as below.

{ "name" : "App" , "version" : "0.1.0" , "homepage" : "http://localhost:8080/sampleapp" , "private" : true , "dependencies" : { "react" : "^16.3.1" } , "scripts" : { "start" : "react-scripts start" , "build" : "react-scripts build" , "test" : "react-scripts test --env=jsdom" , "eject" : "react-scripts eject" } }

Most of the hosting services which supports javascript and html supports reactjs hosting as well , as it runs on client side .So to deploy react app it is not difficult but your app needs a backend server as well .Hence complexity increases and i faced this while deploying a react app to a servlet container like tomcat . Let me know in your commnets if you have faced any similar sort of trouble deploying react app.

Related Posts :-