# Dockerizing React Apps

Containerized development is hot 🔥  What makes these tools so popular? From my experience, containers:

- Make complex local environments quick and easy to spin up
- Allow for specific versioning of languages and packages to coexist locally
- Provide an easy tool to ship code for pipeline integration and deployment
- Help create a consistent work environment across developers

Docker has taken the spotlight for creating development containers. This tutorial will show you how to dockerize a project created with Create React App.

## Prerequisites

In order to go through this tutorial, you should have [node](https://nodejs.org/en/) (LTS version if you're uncertain) and [docker](https://docs.docker.com/get-docker/) installed. The links just listed should work for you, but feel free to use [Homebrew](https://brew.sh/) or installer you prefer.

## Project Startup

If you don't have a CRA project yet, use `npm` to create a new one using the `npx` command:

```jsx
npx create-react-app my-project
```

Move into your project:

```jsx
cd my-project
```

Start up and check out your app:

```jsx
yarn start
```

It soon should be running at [http://localhost:3000](http://localhost:3000). When you've had your fun exploring, turn off the server when with `ctrl+c` and get ready to start dockerizing 🤓

## Dockerize!

New docker images are built on a base image and ours will be no different. [Docker hub](https://hub.docker.com) contains a multitude of images. It is probably no surprise that we will be using a [node docker image](https://hub.docker.com/_/node) as our base (we'll use `14.15.1` which is LTS at the time of writing). 

To specify this docker image and other configuration, create the file `Dockerfile` in the root of your project and add the following:

```docker
# pull official base image
FROM node:lts-alpine

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# copies package.json and package-lock.json
COPY package*.json ./

# installs app dependencies
RUN npm install
RUN npm install react-scripts -g

# add app contents to the container
COPY . ./

# start app
CMD ["npm", "start"]
```

Let's break this down line by line

1. `FROM node:lts-alpine`
This line tells docker what base image to use. We want to use the latest stable (LTS stands for long term stable) version of node. Alpine is a distribution of linux that is designed for security, simplicity, and resource efficiency. It is a common choice for docker images because of this.
2. `WORKDIR /app`
It's good practice to chose a working directory to enter into. If you don't, docker will copy all the contents into the root of the image. If there is namespace clashes, there may be 

Also, create a `.dockerignore` file in the root of your project with the following content:

```docker
node_modules
build
.dockerignore
Dockerfile
Dockerfile.prod
```

This makes sure not to copy any unnecessary files to our docker image.

## Start Up Docker

First, we need to build the docker image:

```docker
docker build . -t local-react
```

The `-t local-react` is a tag to easily reference our docker container later. You can change `local-react` to whatever name you want, just make sure you change the next script as well!

You should see the steps from the above `Dockerfile` run. Then we can start up our docker server with this command:

```docker
docker run \
  -it \
  --rm \
  -v ${PWD}:/app \
  -v /app/node_modules \
  -p 3000:3000 \
  local-react
```

Let's go through what's happening here line by line

1. `docker run` starts up the docker container
2. `-it` runs the docker container in interactive mode so that the container remains open after it starts. As of [react-scripts v3.4.1 this is now required]([https://stackoverflow.com/questions/60790440/docker-container-exiting-immediately-after-starting-when-using-npm-init-react-ap](https://stackoverflow.com/questions/60790440/docker-container-exiting-immediately-after-starting-when-using-npm-init-react-ap)).
3. `-v ${PWD}:/app` creates a volume of your current working directory into the app directory. This way, when changes are made locally, they will be reflected in docker
4. `-v /app/node_modules` is a workaround to ensure that we use the `node_modules` in the docker container rather than the `node_modules` locally
5. `-p 3000:3000` exposes the docker port 3000 on your [localhost](http://localhost:3000) so you can view the app running
6. `local-react` is the tag of the container we built

Boom 🎉 With any luck you should be up and running!

