DEV Community

Cover image for Dockerizing a React App
Malik Idrees
Malik Idrees

Posted on • Edited on

Dockerizing a React App

Let's do it

We are going to create a MERN Stack boilerplate using docker which can serve as a base to create other apps as well.

A quick note: react is ready to go in production. but backend (nodejs) could be improved further. So you could also focus only on react!

Feel free to comment if you have optimitized nodejs API's using pm2 etc.

Now let's create our project.

project
└───backend
          - index.js
          - .env
└───frontend
Enter fullscreen mode Exit fullscreen mode

First we are going to create our backend and frontend and then we will move on to dockerize them.

Lets setup our backend first.

$ cd backend
$ npm init
If you want to skip these questions
$ npm init -y

It createspackage.json. The package.json file holds some basic information about your application as well as metadata about your app. Add inside package.json add:(enables ES 6 modules, u can use import syntax)

"type": "module",
Enter fullscreen mode Exit fullscreen mode

Let's install express server.
$ npm i express
$ npm i dotenv

Replace .env with below:

NODE_ENV = development
PORT = 5000
Enter fullscreen mode Exit fullscreen mode

Replace index.js with below code

import express from 'express'
import dotenv from 'dotenv'

dotenv.config()

const app = express()

app.get('/', (req, res) => {
    res.send('API is running')
})

const PORT = process.env.PORT || 5000

app.listen(PORT, () =>
    console.log(`
Server running in ${process.env.NODE_ENV} mode on ${PORT} Port`)
)
Enter fullscreen mode Exit fullscreen mode

Test if our app is running
$ node backend/index.js It should be available at http://localhost:5000/

Lets do frontend now.

Make sure you are inside frontend folder. Let's creates a react app. But hot reloading does not work well with react-scripts @5.0.0 (At the time of writing)
$ cd frontend
$ npx create-react-app ./
So for now you could use this.
$ cd root
$ npx create-react-app ./client --scripts-version 4.0.3
$ cd client
$ npm run start our app should be available at https://localhost:3000/

Now we are going to dockerize our app.

Docker file Server

$ cd backend
Create a .dockerignore file.

node_modules
Dockerfile
.gitignore
.git
Enter fullscreen mode Exit fullscreen mode

Create a Dockerfile without any extension.

FROM node:16.14.0-slim

#create app directory inside docker
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install

#Bundle source code
COPY . .
EXPOSE 5000

CMD ["npm","run","dev"]

Enter fullscreen mode Exit fullscreen mode
let's build our docker image Server

$ docker build -t backend .
To run our container
$ docker run -p port 4000:5000 backend
To run with hot reloading use this command and remove container at the end.
$ docker run --rm -it -p 5000:5000 -v ${PWD}:/usr/src/app --name app-backend backend
available at https://localhost:4000/

Docker file frontend

$ cd frontend
Create a .dockerignore file.

node_modules
Dockerfile
.gitignore
.git
Enter fullscreen mode Exit fullscreen mode

Create Dockerfilewithout any extension

FROM node:16.14.0-slim
# Working directory
WORKDIR /user/src/frontend
# Install dependencies
COPY package*.json ./
RUN npm install
# Copy local files to frontend folder
COPY . .
EXPOSE 3000

CMD ["npm","start"]
Enter fullscreen mode Exit fullscreen mode

Create Dockerfile.prod file for production builds

FROM node:16.14.0-slim AS build-stage
ENV NODE_ENV production
# Add a work directory
WORKDIR /user/src/frontend
# ENV PATH /app/node_modules/.bin:$PATH
# Cache and Install dependencies
COPY package*.json ./
# COPY yarn.lock .
RUN npm install --production
# Copy app files
COPY . .
# Build the app

RUN npm run build

FROM nginx:1.21.6-alpine
ENV NODE_ENV production
# Copy built assets from builder
COPY --from=build-stage /user/src/frontend/build /usr/share/nginx/html
# Add your nginx.conf
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
Enter fullscreen mode Exit fullscreen mode
Docker Compose

Instead of typing those long command through terminal. Compose files allow us to manage container easily.

Create docker-compose.yml file
$ cd root

version: '3'
services:
  frontend:
    container_name: react-dev
    build:
      context: ./frontend
    ports:
      - 3000:3000
    env_file: ./frontend/.env
    environment:
      - NODE_ENV=development
      - CHOKIDAR_USEPOLLING=true
    volumes:
      - ./frontend:/user/src/frontend
      - /user/src/frontend/node_modules
Enter fullscreen mode Exit fullscreen mode

Create docker-compose.prod.yml file for production builds(React only)
$ cd root

version: '3'
services:
  frontend:
    container_name: react-prod
    image: react-prod
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod
    ports:
      - 1337:80
    env_file: ./frontend/.env
Enter fullscreen mode Exit fullscreen mode
Some useful Docker commands

Show all containers in running state.
$ docker ps or newer version $ docker container ls
To show all running and exited container
$ docker ps -a or $ docker container --all
Run a container bash session.
$ docker exec -it <container name> bash
Run a image bash session.
$ docker run -it <image name> bash
$ docker run -it backend bash then$ node -v prints node version.
To pull base images before using them e.g.
$ docker pull <image name>
$ docker pull node:16.14.0-slim
Run your image (backend) as a container(app-backend).
$ docker run -p 2000:5000 --name app-backend backend
To start existing container.
$ docker container start <container name>
To stop an existing container.
$ docker stop <container name>
To remove a container.
$ docker rm <container name>
To stop all container
$ docker stop $(docker ps -a -q)
To remove all container
$ docker rm $(docker ps -a -q)

MERN Stack template

We are going to create a MERN Stack boilerplate which can be extended for other use cases. Run it locally or on Docker.

project
└───backend
└───frontend
└───.env
Lets setup our backend first.

$ cd backend
$ npm init
If you want to skip these questions
$ npm init -y

It creates package.json. The package.json file holds some basic information about your application as well as metadata about your app. Add inside package.json add:

"type": "module",
Enter fullscreen mode Exit fullscreen mode

Let's install express server $ npm i express
$ npm i dotenv

Replace .env with below:

NODE_ENV = development
PORT = 5000

Replace index.js with below code

import express from 'express'
import dotenv from 'dotenv'
dotenv.config()

const app = express()

app.get('/', (req, res) => {
    res.send('API is running')
}
Enter fullscreen mode Exit fullscreen mode

ps: somehow the changes in react part is missing from repo. Create a pull request!

LinkedIn: LinkedIn
GitHub: Link
Fiverr: imidrees
Thanks for reading!

Top comments (1)

Collapse
 
zodman profile image
Andres 🐍 in 🇨🇦

I recommend to put that containers and manage with dokku :>