Stop Running Your Project Locally

Run in Docker container instead (the easy way)

Alan Zhao
3 min readJun 19, 2023

Intro

The typical development workflow for a React application would be as follows, as an example:

npx create-react-app my-app
cd my-app
npm install
npm run start

Well, nothing wrong with that. Your latest Node 18 project might be fully compatible with Node 16 that is currently installed. You don’t notice a thing and move on.

Why

As the number of your project grows and you run into compatibility issues. You then install multiple versions of node and npm and switch between versions using nvm as needed.

You’re doing it wrong!

As a best practice, if your project builds static files, your development environment should match the production CI/CD build environment. If your project runs inside a Docker container on production, the development environment should run in the same Docker container.

Say no to locally spun up ad-hoc environments.

How

In this article, I am building a React application and I know the CI/CD will build static files with a Docker image. Therefore, I want my development environment to match the CI/CD build environment to avoid any deviation and unforeseeable bugs caused by the environment differences.

Install Docker if you don’t already have.

First, create a Dockerfile.dev to define your development environment. As you can tell, it copies the whole project into the Docker container's app directory and run npm install there. You won’t see node_modules being installed locally.

FROM public.ecr.aws/amazonlinux/amazonlinux:2023

RUN dnf update -y
RUN dnf install -y nodejs

# All of above should match your production build environment

WORKDIR /app
COPY ./ ./
RUN npm install

EXPOSE 4040

CMD [ "npm", "run", "start" ]

Next, create a helper script run-dev.sh as follows and run it to start the Docker container. Open your browser on https://localhost:4040 to view your application. That’s it.

#!/bin/bash

DOCKER_APP_NAME=my-app-dev

# Remove old image
docker image rm -f $DOCKER_APP_NAME || true

# Build new image
docker build -t $DOCKER_APP_NAME -f Dockerfile.dev .

# Run new container, redirect logs to current console `-t`,
# allow process to exit gracefully using CTRL + C `--init`
# remove container when it exits `--rm`,
# map host port 4040 to container port 4040 `-p 4040:4040`
# map current src directory to container's /app/src directory `-v $(pwd)/src:/app/src`
# give container a name `--name $DOCKER_APP_NAME`
docker run -t --init --rm -p 4040:4040 -v $(pwd)/src:/app/src \
--name $DOCKER_APP_NAME $DOCKER_APP_NAME

The helper script should be self-explanatory. It will build a new Docker image and container every time, it maps container’s app/src directory to the local src directory for hot-reloading, and you will continue to see the logs in your console.

This project will be built with AWS CodeBuild using image aws/codebuild/amazonlinux2-x86_64-standard:5.0 which I know has the identical Docker image as defined in Dockerfile.dev.

Benefits

  • Your development environment will be OS agnostic
  • Development and production environments match
  • Ability to build legacy projects without installing any packages locally
  • Projects can be easily shared within team

Hope this helps.

--

--

Alan Zhao
Alan Zhao

Written by Alan Zhao

Solutions Architect & Software Engineer

No responses yet