M. Akbar Nugroho
Posted on October 7, 2022
With the popularity of cloud computing, containerization is a common technique used for mid to large scale project because it gives us isolated, scalable and easy way to deploy our application.
Today we are going to learn and create a production-ready docker image for React.js application. I really exited with this one so, let's start it out 😼.
Requirement
First, ensure Docker is installed on your machine. If you haven't please install it and come here again.
docker -v
Then, ensure Node.js is also installed on your machine. We need this to bootstrap our React.js application.
node -v
Initialize a Project
Theres so many ways to intializing React.js application. Either manually, pre-built template or front-end tools.
In this article we are going to use front-end tool called Vite because it's fast and configurable.
HINT
You may use Create React App (CRA) to intialize your application. It's also good and developed by Facebook Open Source too.
Open your terminal and type the following command.
npm create vite@latest docker-production-react
A prompt will appear. Just select React and JavaScript.
Now move to folder docker-production-react
and run the following command.
npm i
HINT
npm i
is just aliased command fornpm install
.
To ensure the initialize process works fine, let's start the local server.
npm run dev
Open with your browser http://localhost:5173
and you should see something like this.
Create Custom Docker Image
In this article, we'll using a technique called multi-stage build. Our goals is to separate the build process of React.js application itself and the web server (to serve the website).
Setup For Build Process
First, inside docker-production-react
create a Dockerfile
file and follow snippet below.
Here, we are using 16.17.1-alpine3.16
. I choose alpine linux because it's tiny so, it make build process faster.
FROM node:16.17.1-alpine3.16 as build
WORKDIR /usr/app
COPY . /usr/app
RUN npm ci
RUN npm run build
The snippet above tells Docker to pull (when hasn't pulled) or use pulled image from Docker Hub to use node:16.17.1-alpine3.16
as the base image for build stage, set the current directory to /usr/app
, running npm ci
and finally build the application using npm run build
command.
Setup For Web Server
Because React.js application is a static files, we need a simple, yet performant we web server in order the user able to access the application. Therefor I choose Nginx to handle this job.
From the previous Dockerfile
, follow this snippet.
FROM nginx:1.23.1-alpine
EXPOSE 80
COPY ./docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /usr/app/dist /usr/share/nginx/html
Here we tell Docker to use nginx:1.23.1-alpine
as the base image and exposing port 80 (default port Nginx), copy the configuration file and copy our bundled application.
HINT
Because Nginx act as a common web server and only serve our application, it's OK to not bind the configuration file at runtime.
For the Nginx configuration file, create default.conf
file inside docker/nginx/conf.d
.
mkdir -p docker/nginx/conf.d; touch docker/nginx/conf.d/default.conf
...and follow below snippet.
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
The configuration just serve our application, but you can customize it as your needs.
Here our final Dockerfile
...
FROM node:16.17.1-alpine3.16 as build
WORKDIR /usr/app
COPY . /usr/app
RUN npm ci
RUN npm run build
FROM nginx:1.23.1-alpine
EXPOSE 80
COPY ./docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /usr/app/dist /usr/share/nginx/html
.dockerignore
It's similar with .gitignore
, but it's used when you build your Docker image.
touch .dockerignore
Put it inside .dockerignore
.git
.DS_Store
.env
node_modules
IMPORTANT
Never put sensitive information inside your Docker image. Exclude it using
.dockerignore
.
Build Phase
Execute this command to build our image.
docker build -t web:0.1.0 .
Ensure the image is available.
docker image ls
Testing
Let's verify our works.
docker run --rm --name web-1 -p 80:80 -d web:0.1.0
Now open http://localhost
with your browser and you should see something like this.
Yeay! It's working...
Bonus: The Source Code
Find it here.
Also follow my latest experiment.
Posted on October 7, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.