2

In summary, while attempting to build a Django, React, and Vite application, I'm encountering an issue with npm installation within a Docker container.

Initially, both the npm & Node.js installations were not executing in the container. However, I resolved the Node.js failure after adding two COPY commands referenced in my Dockerfile.

However, even after trying many configurations, the npm failure persists.

Checking Node.js installation inside the container:

% docker exec -it docktest-web-1 node -v
  v14.21.3

Checking npm installation inside the container:

% docker exec -it docktest-web-1 npm -v
  OCI runtime exec failed: exec failed: unable to start container process: exec: "npm": executable file not found in $PATH: unknown

*The build still completes successfully, but npm is not installed in the container.


The relevant aspects of my configuration are as follows:

Dockerfile

# Use the official Node.js image for frontend build
FROM node:14 as frontend-build

# Set the working directory for the frontend build
WORKDIR /frontend

# Copy only the package.json to take advantage of Docker caching mechanism
COPY frontend/package.json ./

# Copy the rest of the frontend code to the container
COPY frontend/ .

# Install frontend dependencies
RUN npm cache clean --force
RUN npm install vite -g
RUN npm install npm@latest -g

# Build the frontend
RUN npm run build

# Create main container for Django and PostgreSQL
FROM python:3

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV NODE_PATH=/usr/local/lib/node_modules

# Without these two lines,the Node.js installation failed as well
COPY --from=frontend-build /usr/local/bin/node /usr/local/bin/
COPY --from=frontend-build /usr/local/lib/node_modules/ /usr/local/lib/node_modules/

# Set the working directory for Django
WORKDIR /code

# Copy the backend requirements and install dependencies
COPY requirements.txt /code/
RUN pip3 install -r requirements.txt

# Copy the frontend build from the previous stage to the working directory of the main container
COPY --from=frontend-build /frontend/ /code/frontend/

# Copy the frontend
COPY . /code/

docker-compose.yml

services:
  db:
    image: postgres
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
      - /code/frontend/  # Exclude frontend folder from being mounted to avoid conflicts
    ports:
      - "8000:8000"
    environment:
      - POSTGRES_NAME=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    depends_on:
      - db

Addendum – Update 8/1:

  1. If visiting this post with similar issues, after reviewing the "Accepted Answer" the create-vite templates in the Vite.js GitHub Repository are very helpful for configuring package.json with Vite and React dependencies. Initial link suggested by @Phil linking to Vite Documentation.
  2. To resolve the following Vite/React error (below), the suggested solutions in this post: Configure Vite to Allow JSX Syntax proved very helpful as well:
[ERROR] The JSX syntax extension is not currently enabled
DAK
  • 116
  • 1
  • 10
  • @Phil I am trying to use Vite to bundle React on the frontend, while using Django on the backend using a multi-stage build – DAK Aug 01 '23 at 00:29
  • That is a [multi-stage build](https://docs.docker.com/build/building/multi-stage/) which results in a single image – Phil Aug 01 '23 at 00:36
  • @Phil Then I've clearly misinterpreted the Docker docs... Do you have any docs I can look at, or other suggestions? This is my first rodeo with Docker, so I've been trying to figure it out on the fly. To clarify, is this the source of the error? – DAK Aug 01 '23 at 00:39
  • That depends, are you trying to run these apps in a production-like configuration or are you trying to use this for development? Do you want to run the Vite dev-server or do you want to build the React app and serve it statically? – Phil Aug 01 '23 at 00:44
  • @Phil Currently for development, but wanted to run in a production-like configuration. Originally I was attempting to serve the React app statically with Django. However, I was not getting the benefit of Vite's HMR. I don't know if this was a configuration error or expected behavior in that config (I was *also* getting an `unexpected token error` when trying to serve the React files - unsure if it was related). However, since then, I had been trying to run the Vite dev-server to get the benefit of HMR, but I couldn't do that without installing npm. – DAK Aug 01 '23 at 00:53
  • Your `package.json` is missing all its `dependencies`. How did you generate it? I would use one of the existing [Vite templates](https://vitejs.dev/guide/#scaffolding-your-first-vite-project), eg `npm create vite@latest frontend -- --template react` – Phil Aug 01 '23 at 06:49
  • 1
    @Phil Realized I uploaded the version I had been chopping line by line during debugging, but had forgotten to revert. Nevertheless, I was still missing dependencies in that file, so thank you for another incredibly helpful suggestion. I am going to remove the Addendum code, and just note the suggestion in the post. Thanks again for all your help. – DAK Aug 01 '23 at 15:01

1 Answers1

1

You appear to be trying to run separate services for front-end and back-end. The issue is that you're producing a single image for both which will be difficult to manage.

I would set up separate compose services with their own build contexts for each. If you plan on supporting both development and production-like configurations, I'd recommend separate Docker and compose files too.

For example, this is a development configuration with volume mounts for your source code and running the Vite dev-server with HMR.

# ./frontend/Dockerfile.dev

FROM node:14-alpine # it's seriously time to upgrade https://endoflife.date/nodejs

WORKDIR /app
EXPOSE 5173

COPY package*.json .
RUN npm install

# no need to copy other files since we'll volume-mount them

CMD ["npm", "run", "dev", "--", "--host"]
# ./Dockerfile.dev
# You may want to consider putting your backend code into its own folder too

FROM python:3

WORKDIR /code
EXPOSE 8000

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip3 install -r requirements.txt

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
# docker-compose.yaml
# ...

react:
  build:
    context: ./frontend
    dockerfile: Dockerfile.dev
  ports:
    - "5173:5173"
  volumes:
    - ./frontend:/app
    - /app/node_modules

django:
  build:
    context: .
    dockerfile: Dockerfile.dev
  ports:
    - "8000:8000"
  volumes:
    - .:/code
  environment:
    - POSTGRES_NAME=postgres
    - POSTGRES_USER=postgres
    - POSTGRES_PASSWORD=postgres
  depends_on:
    - db

A production build would look more like your original Dockerfile, using a multi-stage build to compile your React app then copy it into Django's static serving directory (note: I'm not a Python dev but it seems a fairly straight forward configuration based on this article)

# Dockerfile

# Frontend build
FROM node:14-alpine AS frontend-build
ENV NODE_ENV=production
WORKDIR /build

COPY frontend/package*.json .
RUN npm ci

COPY frontend .
RUN npm run build

# Backend build
FROM python:3

WORKDIR /app
EXPOSE 8000

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

COPY requirements.txt .
RUN pip3 install -r requirements.txt

COPY . .
COPY --from=frontend-build /build/dist ./staticfiles # ¯\_(ツ)_/¯

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Phil
  • 157,677
  • 23
  • 242
  • 245
  • 1
    You seriously cannot begin to understand how grateful I am for your help...THIS IS IT!!! I've literally spent 20 working hours trying everything I could think of to get this running, and this is the answer! I know comments aren't meant for this, but I wanted to let you know how appreciative I am – I wish there was something I could do in return! Thank you so much! – DAK Aug 01 '23 at 04:51
  • @DAK you're very welcome – Phil Aug 01 '23 at 05:12
  • Apologies, don't want to push my luck but, per your suggestion, I've added a `backend/` sub-directory with the Python Dockerfile/dependencies. However, the Django server returns a 404 error (works fine when in root). I've tried updating `docker-compose` with `dockerfile: ./backend/Dockerfile`, and `volumes: ./backend:/code`, then setting `context: ./backend`. Also tried setting `context: .` then copying `/frontend` directory to the `/backend` Dockerfile. Maybe it's a Django config issue, but wanted to ask if you had any suggestions since you mentioned it. – DAK Aug 01 '23 at 23:38
  • @DAK probably too big to tackle in the comments but if you moved all the Django code into `./backend`, you'd use `context: ./backend` and `dockerfile: Dockerfile.dev`. I'd be no help diagnosing Django issues. Like I said, I'm no Python dev – Phil Aug 01 '23 at 23:58
  • Yeah no worries, it's more than likely a Django config issue since that's the docker-compose setup I've used. I'll figure it out – thanks again. – DAK Aug 02 '23 at 00:03