Dockerizing a React App
Tags: react, docker, webdev, devops
Published: 2022-07-16 14:02:00

#### 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
```
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 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:(enables ES 6 modules, u can use import syntax)

```javascript
"type": "module",
```

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

```javascript
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`)
)
```

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
```

Create a `Dockerfile` without any extension.

```Docker
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"]

```

##### 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
```
Create `Dockerfile`without any extension
```Docker
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"]
```

Create `Dockerfile.prod` file for production builds
```Docker
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;"]
```
##### 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`
```Docker
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
```

Create `docker-compose.prod.yml` file for production builds(React only)
`$ cd root`
```Docker
version: '3'
services:
  frontend:
    container_name: react-prod
    image: react-prod
    build:
      context: ./frontend
      dockerfile: Dockerfile.prod
    ports:
      - 1337:80
    env_file: ./frontend/.env
```

##### 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) `

{% embed https://github.com/Malik-Idrees/mern-template-docker %}

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

LinkedIn: [LinkedIn](https://www.linkedin.com/in/malikidrees/)
GitHub: [Link](https://github.com/malik-idrees) ⭐
Fiverr: [imidrees](https://www.fiverr.com/share/27Yy04) ✨
Thanks for reading!