Okay, you have a frontend React app and you want to serve it via Docker. Let's do that!
In this wiki, we will dockerize both the development and production environment via separate Dockerfiles.
Step 1: Project setup
Initialized a pretty standard react project using the default create react app (CRA) template. Or pick your existing React app. Below is the sample project folder structure.
node_modules
public
favicon.ico
index.html
manifest.json
robots.txt
src
App.css
App.js
index.css
index.js
logo.svg
package.json
yarn.lock
Step 2: Init .dockerignore
Add a .dockerignore
file, this will help us ignore node_modules
, .env
etc
.git
.gitignore
**/node_modules
**/npm-debug.log
build
Step 3: Dockerize Development env
Init Dockerfile
Start by adding a Dockerfile.dev
FROM node:14-alpine AS development
ENV NODE_ENV development
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
#RUN yarn install
RUN npm i
# Copy app files
COPY . .
# Expose port
EXPOSE 3000
# Start the app
CMD ["yarn", "start"]
Init docker-compose
Create a docker-compose.dev.yml
. Additionally, we will mount our code in a volume so that our code changes are in sync with the container during development.
version: "3.8"
services:
app:
container_name: app-dev-c
image: app-dev-i
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app/src
ports:
- "3000:3000"
Let's start our React app for development!
docker-compose -f docker-compose.dev.yml up
To make life easier add docker-compose commands to package.json
"docker-dev-up": "docker-compose -f docker-compose.dev.yml up"
"docker-dev-down": "docker-compose -f docker-compose.dev.yml down"
Let's check our container!
> docker ps
REPOSITORY TAG IMAGE ID CREATED SIZE
app-dev latest 5867f4e40c98 About a minute ago 436MB
Visit the app at http://localhost:3000
Step 4: Dockerize Production env
Let's use nginx to serve our static assets and help resolve routes when we're using React Router or any kind of routing.
Configure nginx
Create a nginx.conf
with the below content. This will help handle URI changes during routing.
server {
listen 80;
location / {
root /usr/share/nginx/html/;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html;
}
}
Init Dockerfile
Start by adding a Dockerfile.prod
FROM node:14-alpine AS builder
ENV NODE_ENV production
# Add a work directory
WORKDIR /app
# Cache and Install dependencies
COPY package.json .
COPY yarn.lock .
RUN npm i
# Copy app files
COPY . .
# Build the app
RUN npm run build
# Bundle static assets with nginx
FROM nginx:1.21.0-alpine as production
ENV NODE_ENV production
# Copy built assets from builder
COPY --from=builder /app/build /usr/share/nginx/html
# Add your nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
Init docker-compose
Add a docker-compose.prod.yml
file
version: "3.8"
services:
app:
container_name: app-prod-c
image: app-prod-i
build:
context: .
dockerfile: Dockerfile.prod
ports:
- "8080:80"
Build production image
docker-compose -f docker-compose.prod.yml build
Let's check out our built production image
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
app-prod latest c5db8d308bb9 About a minute ago 23.1MB
Start our production container on port 80
with the name react-app
docker run -p 8080:80 --name react-app app-prod
Visit the app at http://localhost:
8080
Here is how the final project struct looks:
node_modules
public
index.html
...
manifest.json
src
App.css
...
index.js
package.json
yarn.lock
.dockerignore
Dockerfile.dev
Dockerfile.prod
docker-compose.dev.yml
docker-compose.prod.yml
Hurrayyy!! We can now use docker in our workflow and deploy our production images faster to any platform.
Top comments (0)