16

I was wondering if anyone had any experience using create-react-app with docker. I was able to get it set up with a Dockerfile like:

from node
RUN mkdir /src
WORKDIR /src
ADD package.json /src/package.json
RUN npm install
EXPOSE  3000
CMD [ "npm", "start" ]

And then used a docker-compose file like:

app:
  volumes:
    - "./app:/src"
  ports:
    - "3000:3000"
    - "35729:35729"
  build: ./app

This allowed me to start up the container and view the app. However livereload didn't work when saving files in the mounted volume and webpack created several .json.gzip files in the src directory.

Any suggestions for getting this working correctly?

john_ryan
  • 1,557
  • 1
  • 16
  • 34
  • 2
    I think docker is not the right tool for what you want to have. Just develop on yout machine with live reloading and other features you like and build containers/images for released version only or for automated testing... It's not clear why you need docker for development here... – aholbreich Aug 04 '16 at 10:23
  • 1
    livereload should work if you're using Docker for Mac, or using docker on linux. If you're still using Docker Toolbox (with a VM) it has been reported that file watching often doesn't work. – dnephin Aug 04 '16 at 14:14
  • 1
    @dnephin thanks for the tip switched to Docker for Mac and everything works great. – john_ryan Aug 04 '16 at 15:19
  • @aholbreich I think you might be right, my thought was to wrap everything (including the backend i'm working on) in a docker compose setup to deal with CORS but I think that is likely overkill. – john_ryan Aug 04 '16 at 15:19

7 Answers7

9

Yeah, as aholbreich mentioned, I'd use npm install / npm start locally on my machine for development, just because it's so easy. It's probably possible with docker-compose, mounting volumes etc. too, but I think it could be a bit fiddly to set up.

For deployment you can then very easily use a Dockerfile. Here's an example Dockerfile I'm using:

FROM node:6.9

# Create app directory
RUN mkdir -p /src/app
WORKDIR /src/app

# to make npm test run only once non-interactively
ENV CI=true

# Install app dependencies
COPY package.json /src/app/
RUN npm install && \
    npm install -g pushstate-server

# Bundle app source
COPY . /src/app

# Build and optimize react app
RUN npm run build

EXPOSE 9000

# defined in package.json
CMD [ "npm", "run", "start:prod" ]

You need to add the start:prod option to your package.json:

"scripts": {
  "start": "react-scripts start",
  "start:prod": "pushstate-server build",
  "build": "react-scripts build",
  "test": "react-scripts test --env=jsdom",
  "eject": "react-scripts eject"
},

You can run the tests on your CI service with:

docker run <image> npm test

There's nothing stopping you from running this docker container locally as well to make sure things work as expected.

metakermit
  • 21,267
  • 15
  • 86
  • 95
7

I recently made a small project called hello-docker-react who just does what the op is looking for.

It's made with docker-compose, create-react-app, yarn, a node image, and a small entrypoint script.

Live reload work flawlessly and I haven't found any problems yet.

https://github.com/lopezator/hello-docker-react

sh4
  • 1,217
  • 13
  • 20
4

here is good gide for this https://mherman.org/blog/dockerizing-a-react-app/

for development

# base image
FROM node:9.6.1

# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

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

# install and cache app dependencies
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts@1.1.1 -g --silent

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

for production

# build environment
FROM node:9.6.1 as builder
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
ENV PATH /usr/src/app/node_modules/.bin:$PATH
COPY package.json /usr/src/app/package.json
RUN npm install --silent
RUN npm install react-scripts@1.1.1 -g --silent
COPY . /usr/src/app
RUN npm run build

# production environment
FROM nginx:1.13.9-alpine
COPY --from=builder /usr/src/app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Ryabchenko Alexander
  • 10,057
  • 7
  • 56
  • 88
2

Not exactly a direct improvement of the author's code, but I was able to get a development environment working with very little code - and no direct dependency to node on my machine - like this:

docker-compose.yml

services:
  node:
    image: node:16
    user: "node"
    command: "npm start"
    working_dir: /app
    volumes:
      - ./:/app
    ports:
      - 3000:3000

This way, you avoid creating docker images from a Dockerfile.

Usage is generally like this:

  • install dependencies before running: docker compose run node npm install
  • run development environment: docker compose up
  • install new dependencies: docker compose run node npm install [package name]
  • clean up docker instances created with compose run: docker compose rm
Eric
  • 53
  • 5
1

While using docker in development with create-react-app, i discovered that it is possible to override the webpackDevServer configuration by adding CHOKIDAR_USEPOLLING=1to your .env file. This will make the file watching work again. It even refreshes the browser page on the host! The only thing that i discovered is that it doesn't open up a webpage automatically.

I can also advise to add tty: true to your service to have your original console output back into your terminal. To remove the container name prefixes in the logs, you can run something like this after running docker-compose up -d:

docker-compose logs -f --tail=100 client | cut -f2 -d \"|\""
Donny Verduijn
  • 424
  • 6
  • 10
1

Running with CRA 4.0 and many dependencies

.dockerignore

.git
.gitignore
node_modules
build

Dockerfile.dev

FROM node:alpine

WORKDIR /app

COPY package.json /app

RUN yarn install

COPY . .

CMD ["yarn", "start"]

docker-compose.dev.yml

version: "3.8"
services:
  print:
    stdin_open: true
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ".:/app"
      - "/app/node_modules"

Dockerfile.prod

FROM node:alpine as build

WORKDIR /app

COPY package.json /app

RUN yarn install

COPY . /app

RUN yarn run build

FROM nginx:stable-alpine
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html

docker-compose.prod.yml

version: "3.8"
services:
  print:
    stdin_open: true
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:
      - "80:80"

nginx.conf

server {  
  listen 80;
  server_name frontend;
  location / {
    root /usr/share/nginx/html;
    index index.html;
    try_files $uri /index.html;
  }
}

To run

docker-compose.exe -f .\docker-compose.yml up --build

or

docker-compose.exe -f .\docker-compose.dev.yml up --build
Xavier Lambros
  • 776
  • 11
  • 19
0

Here is a simple (pure docker) solution without local installation of runtime (e.g. node):

cd /tmp
docker run -it --rm -v "$PWD":/app -w /app node  yarn create react-app my-app
sudo chown -R $USER:root my-app/
cd my-app
nano docker-compose.yml  # see docker-compose.yml below
docker compose up -d

docker-compose.yml:

  services:
      node:
        image: node:16-alpine
        environment:
          - CHOKIDAR_USEPOLLING=true
          - FAST_REFRESH=true
        working_dir: /app
        ports:
          - '3000:3000'
        command: "yarn start"
        volumes:
          - './:/app'

open localhost:3000 in your browser. Hot reload should work out of the box.

oceanBT
  • 204
  • 6
  • 11