0

I'm trying to npm run start a React application which was created with --template typescript. Typescript is therefore installed (as a React dependency) but my Docker container complains with a generic error message that TypeScript wouldn't be installed. I'm therefore unable to start the application inside a Docker container.

Everything works, when I start the application (with the same package.json) outside the container.

Error

> frontend@0.1.0 start /app
> react-scripts start

It looks like you're trying to use TypeScript but do not have typescript installed.
Please install typescript by running npm install typescript.

npm ERR! Exit status 1

I added TypeScript via npm install typescript and rebuilded the Docker container. But it still shows the error message.

Even after adding typescript manually as a dependency (even inside the container with a direct call to npm install typescript there!), the container complained about not being able to find TypeScript (which doens't seem to be true as I can validate that TypeScript was installed inside the container as tsc -version shows me the correct output).

Code

My Dockerfile looks like this:

FROM node:15.4.0-alpine3.12

# set working directory
ARG app_path=/app
WORKDIR ${app_path}

# add `node_modules/.bin` to $PATH
ENV PATH ${app_path}/node_modules/.bin:$PATH

# set Docker port
EXPOSE 3000

# copy configs, no need to copy src files as they get bind mounted later on (see docker-compose)
COPY package*.json ./
COPY tsconfig.json ./

# install all app dependencies
RUN npm install --silent

# validate typescript installation
RUN tsc --version

My docker-compose.yaml file looks like this:

version: '3.8'
services:
  frontend:
    build:
      context: ./frontend
      dockerfile: ../Dockerfile
    image: frontend:dev
    container_name: dev_frontend_react
    ports:
      - 4000:3000
    command: ['npm', 'run', 'start']
    volumes:
      - ${HOST_PROJECT_PATH}/frontend:/app
      
      # add a virtual volume to overwrite the copied node_modules folder as the
      # container installs its own node_modules
      - node_modules:/app/node_modules
    environment:
      - NODE_ENV=development
    restart: unless-stopped

volumes:
  node_modules:
    name: frontend_node_modules

Same question, non working solution

I found another solution to the same question here on StackOverflow: Asked to install Typescript when already installed when building Docker image

But this solution is hard-copying the project into the container and creating an actual build. But that solution is not acceptable for me as it prevents the hot reload feature of React from working.

winklerrr
  • 6,735
  • 2
  • 45
  • 60

1 Answers1

2

During Docker image build (i.e. in the Dockerfile) you are installing the dependencies in to the node_modules folder inside the container (RUN npm install --silent). Type script (tsc --version) works as it gets installed there.

Later, in the docker-compose file, you are replacing the node_modules folder with a folder from the host machine. So, effectively, the commands from the Dockerfile have no effect.

I'm not sure what your goal is, but I can see several options:

  • if you want the docker container to install dependencies into the folder on the host machine (?), you need to do it when the container is being started, not when the image is being build
  • if you just want to use dependencies from the host folder, make sure that the typescript is there
  • if your goal is to run the app on docker but still be able to edit and hot-reload the app, try mounting the src folder alone (but then you won't b able to add new dependencies)

UPDATE:

Actually your solution should work. Docker-compose should copy files from the node_modules inside the container into the mounted volume. There is one gotcha though: it does it only when the volume is newly created (see populate a volume using a container). So, to solve the problem, try removing the volume and rerun docker compose:

docker volume rm frontend_node_modules

Unfortunately you need to do it every time there are any changes to the dependiences. Alternatively you can use:

docker-compose down -v

which will remove volumes as well (by default docker-compose down does not remove volumes, thus the -v switch)

Mafor
  • 5,937
  • 1
  • 10
  • 20
  • I'm trying to use the solution from the answers here: https://stackoverflow.com/questions/30043872/docker-compose-node-modules-not-present-in-a-volume-after-npm-install-succeeds as they describe that the `node_modules` data mount should already be created and accessible at build time – winklerrr Jan 22 '21 at 13:22
  • @winklerrr Right, kind of. Please see the update to my answer. – Mafor Jan 22 '21 at 15:11
  • Your update works for me, thank you! Just as a reference for future readers: Docker CLI documentation for [`docker-compose down`](https://docs.docker.com/compose/reference/down/) – winklerrr Jan 25 '21 at 11:13