While Docker may not have gained significant popularity in front-end development, I believe it can greatly benefit engineering teams, including front-end heavy devs. In my personal experience, front-end developers working with React.js or Angular tend to avoid using Docker.

In the past year, I have actively assisted developers in adopting Docker for their local front-end development environments. This has been particularly helpful in teams where developers are expected to work with multiple front-end apps, frameworks and node versions, etc. Docker’s ability to isolate development setups has made front-end app development smoother and more efficient.

By dockerizing the development environment, another notable advantage is the reduction in the necessity for specific node and build tool installations within the CI (Continuous Integration) environment. While the end result of the build process typically consists of front-end assets like JS bundles, CSS, images, and HTML files, which are ultimately shipped or pushed to a web server like Nginx or hosted on S3, it is important to note that the build pipeline still heavily relies on build tools. However, by dockerizing this process, the development environment is significantly simplified, alleviating the burden of manual tool installation and configuration. This streamlined approach ensures a more efficient and hassle-free build pipeline.

In this article, we will delve into the process of leveraging Docker to create a new ReactJS app.

Create React App

To begin, navigate to your projects directory by executing the following command:

# Navigate to your projects directory
cd ~/my-projects

Next, create a Dockerfile with the following content. This file will serve as the blueprint for building an image to be used as the builder image for creating the React app:

FROM node:20

RUN apt-get update

RUN npm install -g npm@9.7.2 && \
    npm install -g create-react-app

Once the Dockerfile is created, it’s time to build the builder image using the following command:

docker build -t react-app-builder .

To create a React app using the builder image built above, run the following command:

docker run  -it --rm \
            -v "$PWD":/app:rw \
            -w /app  \
            react-app-builder \
            npx create-react-app my-react-app --template=typescript

This command executes a Docker container based on the builder image (react-app-builder) with the necessary configurations. It mounts the current directory ($PWD) as a volume inside the container, sets the working directory to /app, and runs the command npx create-react-app my-react-app --template=typescript.

During this process, you may encounter an error related to initializing git which may not be an issue. The remaining directory structure of the React app will be created successfully.

The command npx create-react-app my-react-app --template=typescript will create a new React app and directory under /app/my-react-app. Since the /app directory is mapped to the host directory ~/my-projects, the resulting app directory will be located at ~/my-projects/my-react-app.

Creating the React app using Docker without the need for Node installation made the process straightforward. This approach can be applied to create apps with other frameworks too, like Angular, Vue.js, Ruby on Rails, and more. Docker provides a versatile solution that eliminates the requirement for specific tools on your local machine, making app creation hassle-free and applicable across various frameworks.

cd my-react-app

Now that we have completed the initial setup, we can proceed to create a Dockerfile specifically for the app. Follow these steps:

  • Delete the builder ~/my-projects/Dockerfile as it is no longer needed.
  • Create a new Dockerfile for the app at my-react-app/Dockerfile with the following content:
# Development stage
FROM node:20 as dev
RUN mkdir /app
WORKDIR /app
COPY package*.json ./app
RUN npm install
CMD ["npm", "start"]

# Build stage
FROM node:20 as build
RUN mkdir /app
WORKDIR /app
COPY package*.json ./app
RUN npm install
COPY . .
RUN npm build

# Production stage
FROM nginx:alpine as prod
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Here’s a quick overview of this Dockerfile:

  • It utilizes Docker’s multi-stage build approach, which allows us to differentiate the tooling and requirements for different stages: local development, build pipeline, and the final artifact deployment.
  • The development stage (dev) is intended for local development and sets up the necessary environment for running the app.
  • The build stage (build) is an intermediate stage that prepares the final artifact for deployment.
  • The production stage (prod) creates an Nginx image with the built React app. This image is used to run the React app as a container within any of the app’s environments.
  • You can refer to this article that explains the need and use of Multi-Stage Docker Builds: Multi-Stage Docker Build Tutorial

Build and Run Locally

Let’s build the app image locally and run it

Navigate to the my-react-app directory:

cd my-react-app

Build the app image targeting the dev stage in the Dockerfile:

cd my-react-app
docker build -t my-react-app-dev --target dev .

This command builds an image named my-react-app-dev specifically for the development stage.

Run the React app as a container:

docker run --rm -it -p 3000:3000 -v $PWD:/app my-react-app-dev

This command executes the app container and runs the command npm start as specified in the Dockerfile under the dev stage. The React app will be accessible at http://localhost:3000 in your browser. Note that the port 3000 inside the container is mapped to port 3000 on the host machine.

Additionally, the volume mount (-v $PWD:/app) ensures that the app code is mounted from the host to the container’s working directory. This allows you to make code changes on the host machine, and the changes will be reflected inside the running container.

You can now make code changes to your React app directly on the host machine, and the changes will be automatically reflected in the running container.

To build the Docker image for production and publish it to a Docker registry as part of your CI/CD pipeline:

docker build -t MYPRIAVTE_REGISTRY/my-react-app-deployable:v1.1 --target prod .

This command builds an image named MYPRIAVTE_REGISTRY/my-react-app-deployable:v1.1 specifically for the production stage. Replace MYPRIAVTE_REGISTRY with your private registry URL.

docker push MYPRIAVTE_REGISTRY/my-react-app-deployable:v1.1

This command pushes the image to the specified Docker registry. Replace MYPRIAVTE_REGISTRY with your private registry URL.

In local development, you also have the option to use docker-compose instead of the plain docker command, which can simplify the setup. Here’s an example docker-compose.yml file that should be placed at the root of the React app code directory, alongside the Dockerfile:

version: "3.8"

services:

  app:
    build:
      context: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app

By using this docker-compose.yml file, you can run the React app locally with a single command: docker-compose up. The app will be accessible at http://localhost:3000 as before.

Summary

In this blog post, we explored how Docker can be used to create a React app and demonstrated the use of Multi-Stage Docker Build to separate the local development and build/deployment stages. The instructions provided in the Dockerfile can be customized to suit your specific needs, such as using different versions of npm or yarn, building more than just assets, and more.

To further expand your knowledge of Docker, I encourage you to try Dockerizing the application you’re currently working on or creating a new one using Docker. The following articles can help you get started with Docker in your local development environment:

Additionally, if you’re interested in learning how to use ChatGPT in creating and running React.js applications using Docker, I recommend checking out the following short videos from the “ChatGPT for Developers” series:

These resources will provide you with valuable insights and practical guidance for leveraging Docker in your development workflow. Happy Dockerizing!