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.