Containerizing your projects with Docker simplifies the development experience and facilitates easy deployment in cloud environments. Let’s take a look at how to package a React site as a Docker container.
This article focuses on projects started with
create-react-app (CRA). If you’ve deleted your CRA configuration or are using a custom build process, you need to get it
npm run build command accordingly.
Docker images are created through a
Dockerfile. This defines a base image to use, such as the Apache web server. You then list a series of commands that add packages, apply configuration changes, and copy files that your application requires.
Defining our requirements
CRA includes a built-in live build and reload system, which you can access via
npm run start. This allows you to quickly repeat your site during development.
When you go to production, you need to compile your static sources with
build directory. You upload these files to your web server.
Could be a basic approach to Dockerising
npm run build local. You would then change the content of it
build directory in your Docker image ̵
This approach is not very scalable, especially when you build your Docker image in a CI environment. Your app build process is not completely encapsulated in the container build, as it relies on the external
npm run build order. We now move on to a more complete example where the entire routine is run in Docker.
A Docker file for CRA
FROM node:latest AS build WORKDIR /build COPY package.json package.json COPY package-lock.json package-lock.json RUN npm ci COPY public/ public COPY src/ src RUN npm run build FROM httpd:alpine WORKDIR /var/www/html COPY --from=build /build/build/ .
Dockerfile contains everything needed to fully containerize the project. It uses Docker’s multi-stage builds to run the React build first and then output to a
alpine Apache server container. This ensures that the final image is as small as possible.
The first part of the file defines the construction phase. It uses the official Node.js base image. The
package-lock.json files are copied in.
npm ci is then used to install the project’s npm packages.
ci is used instead of
install because it enforces an exact match with the contents of
Once the dependencies are installed, the
src folders are copied to the container. The folders are copied after the
npm ci command because they are likely to change much more often than the dependencies. This ensures that the build can take full advantage of Docker’s Layer caching – the potentially expensive one
npm ci command is not executed unless the
package-lock.json files change.
The last step in this build phase is to
npm run build. CRA will compile our React app and export it into it
The second phase in the
Dockerfile is much simpler. The
Using the Docker image
docker build command to build your image:
docker build -t my-react-app:latest .
This builds up the image and tags it as
my-react-app:latest. It uses the
Dockerfile found in your workbook (specified as
The build can take a few minutes. Subsequent builds will be faster because layers such as the
npm ci command is cached between runs.
Once your image is created, you are ready to use it:
docker run -d -p 8080:80 my-react-app:latest
Docker creates a new container with the
my-react-app:latest statue. Port 8080 on the host (your machine) is bound to port 80 in the container. This means you can visit
http://localhost:8080 in your browser to see your React project! The
-d flag is present so that the container runs in the background.
Switch to NGINX
The above example uses Apache, but you can simply switch to NGINX instead.
FROM nginx:alpine COPY --from=build /build/build/ /usr/share/nginx/html
You can use alternative web servers in a similar way; since CRA produces completely static output, you have great flexibility in selecting how your site is hosted. Copy the contents of the
/build/build directory from the
build stage in the default HTML folder of your chosen server software.
Advantages of this approach
Using Docker to not only encapsulate your final build but also create the build itself will make your project fully portable across different environments. Developers only need Docker to build and run your React site.
More realistically, this image is ready for use with a CI server to automatically create images. As long as a Docker environment is available, you can convert your source code to a deployable image without manual intervention.
Using multiphase builds keeps the final image streamlined and should be just a few megabytes in size. The much bigger
node image is only used during the compilation phase, where Node and npm are required.