Deploying the React application having react-router to prod with Express js and Dockerizing the app.

Deploying the React application having react-router to prod with Express js and Dockerizing the app.
react application logo source: react website

During my development career, Usually most of the time, I chose to deploy my front-end applications using Nginx. The Nginx is a widely accepted web server by the community, but during my recent time, I had to deploy my react application behind a sub-path,
My personal preference is to create a subdomain rather than a subpath.
Like most of the time, I choose Nginx, built my react app deployed it, initial screen loaded perfectly, but I had react-router creating the problem with routed URLs. I spent lots of time fixing the Nginx location, and my deadline was very close.
Instead of working hard to find a solution or extending my deadline, I jump ship to an entirely different strategy.
Hola, I deployed my react app Using Express.js and proxy the subpath. And Decided to write a blog about deploying react app with ExpressJS.

Step 1: Let us create our sample react App.

npx create-react-app my-app
cd my-app
npm start 

Step 2: Lets Add React Router And Configure Few Dummy routes.
For adding react-router use npm install react-router-dom --save
also, I am pasting the example reference for the router configuration.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter, Route, Routes } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route index path='/' element={<App/>} />
        <Route index path='/sub-path' element={<App/>} />
        <Route index path='/sub-path/test' element={<App/>} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Step 3: Run the application in development mode and test the routes.

Step 4: Add the attribute "homepage": "." in package.json to build the relative paths while using the build command.

Step 5: Build the resources for deploying by using the following command npm run build.

Step 6: Create the folder called server in the root directory and paste the following package.json file inside the server and run npm install inside the server folder

{
  "name": "server",
  "version": "1.0.0",
  "description": "react deployment using express js",
  "main": "index.js",
  "scripts": {
    "start" : "node ./index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "ashrithgn",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.2"
  }
}

Step 7: Replace/Create the `index.js `contents with the following code

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, '../build')))

// Serve .js files from js staic folder
app.get('*/*.js', (req, res) => {
    const urlParts = req.url.split('/')
    res.sendFile(path.join(__dirname + '/../build/static/js/' + urlParts[urlParts.length - 1]))
})

// Serve .cssfiles from css staic folder
app.get('*/*.css', (req, res) => {
    const urlParts = req.url.split('/')
    res.sendFile(path.join(__dirname + '/../build/static/css/' + urlParts[urlParts.length - 1]))
})

app.get('*/*.css.map', (req, res) => {
    const urlParts = req.url.split('/')
    res.sendFile(path.join(__dirname + '/../build/static/css/' + urlParts[urlParts.length - 1]))
})

// Serve images files from media staic folder
app.get('*/*.(jpg|svg|png|woff|woff2)', (req, res) => {
    const urlParts = req.url.split('/')
    res.sendFile(path.join(__dirname + '/../build/static/media/' + urlParts[urlParts.length - 1]))
})

// Handles any requests that don't match the ones above
app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname + '/../build/index.html'))
})

const port = process.env.PORT || 8080
app.listen(port)

console.log('App is listening on port ' + port)

Basically, this code uses the express.js routes feature to route any HTTP request to the base folder.
FYI: Refer to the comments inside the code where the routes are redirecting to serve the other static files of our build and modify them according to our needs.

Step 8: Inside The server folder run npm run start to serve the build
folder generated in step 5.

Step 9: Generating the docker container

  • Create `Dockerfile`  in the root react app and paste the following content.
FROM node:16-alpine

RUN adduser --uid 10101 --system appuser
WORKDIR /app
COPY ./server ./server
COPY ./build ./build
WORKDIR /app/server
RUN npm install --frozen-lockfile --skip-integrity-check
RUN chown -R appuser /app
USER 10101
EXPOSE 8080
CMD ["npm", "run","start"]
  • Build an image using docker build -t '<name-of-the-image>' ./
  • Run the docker container locally to verify.
  • Deploy the docker container or copy the server and build folder and run in desider web server

Follow me on Medium:

Ashrith g.n – Medium
Read writing from Ashrith g.n on Medium. Every day, Ashrith g.n and thousands of other voices read, write, and share important stories on Medium.

Subscribe to Just Chatterbox

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe