I have talked recently about building docker images for Golang and Python projects, today we'll be focusing on building a Docker image for a React project.
Before continuing make sure to have Node and Docker installed on your machine:
$ node -v
v15.4.0
$ yarn -v
1.22.10
$ docker -v
Docker version 20.10.6, build 370c289
First, let's bootstrap our project using create-react-app
, I'm using the typescript template as an example:
$ npx create-react-app react-sample --template typescript
The app can be started with:
$ cd react-sample
$ yarn start
React app is built and served on port :3000
locally.
Let's create a minimal Dockerfile
:
# Dockerfile
FROM node:15.13.0-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
EXPOSE 3000
CMD ["yarn", "start"]
FROM
: We start with a node image based on alpine OS.WORKDIR
: Set the current directory from this point to be /appCOPY
: Copy the package.json & yarn.lock file inside the container image.RUN
: Install dependencies using yarn install
.COPY
: Copy source code.EXPOSE
: Inform docker which port the server will be exposed to.CMD
: define which command gets executed on startup.Also let's add a .dockerignore
file to avoid adding our local dependencies inside the container image:
# .dockerignore
node_modules/
To build the docker image, start and test it:
$ docker build -t react-sample .
[+] Building 0.8s (10/10) FINISHED
...
$ docker run -d -p3000:3000 react-sample
effa6ecd4d320677b1055cefa82fe32b0eddd136ad17e6e50730e95d91838a25
# wait for server to start
$ docker logs effa6ecd
# open on browser http://localhost:3000
$ docker stop effa6ecd
We started our react app on our previous example but you probably noticed that it takes some time on startup to load, this is because the compilation of our source code is done during container startup instead of the build stage. Also, we have started our react app in development mode, which includes stuff such as watching for file changes and hot-reload.
Instead we want a production build which in react can be done by running yarn build
and placing the output in a static web server such as an nginx
.
We can do that by updating our Dockerfile:
# Dockerfile
# build environment
FROM node:15.13.0-alpine as build
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn build
# runtime environment
FROM nginx:stable-alpine
COPY /app/build /usr/share/nginx/html
COPY /app/nginx/ /etc/nginx/conf.d/
Now our build is done on our build image, and then we use a separate final image which is based on nginx
and we include the output of the previous build and some default config under conf.d/default.conf
:
# /conf.d/default.conf
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
As added benefit since we use multi-stage builds the source code is no longer added in the final image, just the minified production build.
If you're interested in deploying React alongside other apps inside a Kubernetes cluster, this is hopefully a great starting point to prepare your Dockerfile for your React.