Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorporating django-tailwind into existing dockerized cookiecutter-django project? #152

Open
BenA-SA opened this issue Aug 29, 2022 · 7 comments

Comments

@BenA-SA
Copy link

BenA-SA commented Aug 29, 2022

Hi all,

Apologies for what is likely a very simple question, I am pretty new to Docker and am struggling to integrate django-tailwind into my docker project, which was created using cookiecutter-django.

I have tried altering my Dockerfile and local.yml file to follow the Example dockerfiles on the Example app on the django-tailwind github repo but haven't been able make it work. The instructions beyond the example app are not very detailed.

I have quoted my Dockerfile and local.yml file below; would someone be able to advise on what changes I need to make in order to incorporate django-tailwind, or point me in the direction of information that would help me to do it myself?

Thanks for any help anyone can offer!

local.yml

version: '3'

volumes:
  uniqued_local_postgres_data: {}
  uniqued_local_postgres_data_backups: {}

services:
  django: &django
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: uniqued_local_django
    container_name: uniqued_local_django
    platform: linux/x86_64
    depends_on:
      - postgres
      - redis
    volumes:
      - .:/app:z
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

  postgres:
    build:
      context: .
      dockerfile: ./compose/production/postgres/Dockerfile
    image: uniqued_production_postgres
    container_name: uniqued_local_postgres
    volumes:
      - uniqued_local_postgres_data:/var/lib/postgresql/data:Z
      - uniqued_local_postgres_data_backups:/backups:z
    env_file:
      - ./.envs/.local/.postgres

  docs:
    image: uniqued_local_docs
    container_name: uniqued_local_docs
    platform: linux/x86_64
    build:
      context: .
      dockerfile: ./compose/local/docs/Dockerfile
    env_file:
      - ./.envs/.local/.django
    volumes:
      - ./docs:/docs:z
      - ./config:/app/config:z
      - ./uniqued:/app/uniqued:z
    ports:
      - "9000:9000"
    command: /start-docs

  redis:
    image: redis:6
    container_name: uniqued_local_redis

  celeryworker:
    <<: *django
    image: uniqued_local_celeryworker
    container_name: uniqued_local_celeryworker
    depends_on:
      - redis
      - postgres
    ports: []
    command: /start-celeryworker

  celerybeat:
    <<: *django
    image: uniqued_local_celerybeat
    container_name: uniqued_local_celerybeat
    depends_on:
      - redis
      - postgres
    ports: []
    command: /start-celerybeat

  flower:
    <<: *django
    image: uniqued_local_flower
    container_name: uniqued_local_flower
    ports:
      - "5555:5555"
    command: /start-flower

Dockerfile for django:

ARG PYTHON_VERSION=3.9-slim-bullseye

# define an alias for the specfic python version used in this file.
FROM python:${PYTHON_VERSION} as python

# Python build stage
FROM python as python-build-stage

ARG BUILD_ENVIRONMENT=local

# Install apt packages
RUN apt-get update && apt-get install --no-install-recommends -y \
  # dependencies for building Python packages
  build-essential \
  # psycopg2 dependencies
  libpq-dev

# Requirements are installed here to ensure they will be cached.
COPY ./requirements .

# Create Python Dependency and Sub-Dependency Wheels.
RUN pip wheel --wheel-dir /usr/src/app/wheels  \
  -r ${BUILD_ENVIRONMENT}.txt


# Python 'run' stage
FROM python as python-run-stage

ARG BUILD_ENVIRONMENT=local
ARG APP_HOME=/app

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV BUILD_ENV ${BUILD_ENVIRONMENT}

WORKDIR ${APP_HOME}

# Install required system dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \
  # psycopg2 dependencies
  libpq-dev \
  # Translations dependencies
  gettext \
  # cleaning up unused files
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*

# All absolute dir copies ignore workdir instruction. All relative dir copies are wrt to the workdir instruction
# copy python dependency wheels from python-build-stage
COPY --from=python-build-stage /usr/src/app/wheels  /wheels/

# use wheels to install python dependencies
RUN pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* \
	&& rm -rf /wheels/

COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r$//g' /entrypoint
RUN chmod +x /entrypoint

COPY ./compose/local/django/start /start
RUN sed -i 's/\r$//g' /start
RUN chmod +x /start


COPY ./compose/local/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r$//g' /start-celeryworker
RUN chmod +x /start-celeryworker

COPY ./compose/local/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r$//g' /start-celerybeat
RUN chmod +x /start-celerybeat

COPY ./compose/local/django/celery/flower/start /start-flower
RUN sed -i 's/\r$//g' /start-flower
RUN chmod +x /start-flower


# copy application code to WORKDIR
COPY . ${APP_HOME}

ENTRYPOINT ["/entrypoint"]
@mgax
Copy link

mgax commented Aug 29, 2022

You'll have to add tailwind to INSTALLED_APPS in the settings file. Cookiecutter Django looks pretty convoluted, but this looks like the right place: https://github.com/cookiecutter/cookiecutter-django/blob/e8b9253c0b4d4fb08439d81fe175519fdad2dabb/%7B%7Bcookiecutter.project_slug%7D%7D/config/settings/base.py#L77-L92.

FWIW you might be better off following the Django official instructions to start a new project.

@BenA-SA
Copy link
Author

BenA-SA commented Aug 29, 2022

You'll have to add tailwind to INSTALLED_APPS in the settings file. Cookiecutter Django looks pretty convoluted, but this looks like the right place: https://github.com/cookiecutter/cookiecutter-django/blob/e8b9253c0b4d4fb08439d81fe175519fdad2dabb/%7B%7Bcookiecutter.project_slug%7D%7D/config/settings/base.py#L77-L92.

FWIW you might be better off following the Django official instructions to start a new project.

Hi,

Thanks for taking the time to reply.

I have added tailwind to my settings.py - it's more the set up of django-tailwind within docker that I'm struggling with.

I'm not sure what you mean by looking at the official instructions - as far as I'm aware, this is not covered. If you mean starting a new project completely and dropping the using of cookiecutter-django, I have backend uses for cookiecutter-django which means this is not really feasible.

@mgax
Copy link

mgax commented Aug 29, 2022

I have added tailwind to my settings.py - it's more the set up of django-tailwind within docker that I'm struggling with.

Ah, I read the description in a hurry, sorry about that. I think the important bits for the Dockerfile are:

  • Install Node:
    && apt-get install -y nodejs --no-install-recommends \
  • Run manage.py tailwind install to install npm packages:
    RUN SECRET_KEY=nothing python manage.py tailwind install --no-input;
  • Build the tailwind assets and collect Django static files (I'm surprised that collectstatic is not already part of the cookiecutter Dockerfile):
    RUN SECRET_KEY=nothing python manage.py tailwind build --no-input;
    RUN SECRET_KEY=nothing python manage.py collectstatic --no-input;

The example docker-compose.yml includes this bit which runs the Tailwind development server to watch for file changes and rebuild the assets. (FWIW I prefer to run this by hand in another terminal and keep it out of docker-compose.yml):

tailwind:
<<: *default-app
command: "python manage.py tailwind start"
# Without tty, no stdin, and tailwind watcher aborts
# https://github.com/tailwindlabs/tailwindcss/issues/5324
tty: true

@BenA-SA
Copy link
Author

BenA-SA commented Aug 29, 2022

python manage.py tailwind start

Thanks for the detail here, I really appreciate you taking the time to help me out.

I have added the line installing nodejs; however when I try and run the 2nd line (tailwind install), I get an error saying npm hasn't been installed or cannot be found. Any ideas why this might be or how to resolve it?

CommandError: 
It looks like node.js and/or npm is not installed or cannot be found.

Visit https://nodejs.org to download and install node.js for your system.

If you have npm installed and still getting this error message, set NPM_BIN_PATH variable in settings.py to match path of NPM executable in your system.

@mgax
Copy link

mgax commented Aug 30, 2022

@BenAkko Looks like I've missed a line. The example Dockerfile configures the official nodesource package repositories:

&& curl -sL https://deb.nodesource.com/setup_14.x | bash - \
&& apt-get install -y nodejs --no-install-recommends \

Then it installs the nodejs package from the nodesource repo, which comes with npm. Without line 7, the nodejs package from the vanilla Debian repo gets installed, which only recommends the npm package.

@PositivPy
Copy link

PositivPy commented Jan 8, 2023

No, this solution doesn't work.
I've tried to add export NPM_BIN_PATH=$(which nodejs) to no avail.

RUN apt-get update && apt-get install --no-install-recommends -y \
  # dependencies for building Python packages
  build-essential \
  # tailwind dependencies
  nodejs npm \
  # psycopg2 dependencies
  libpq-dev

RUN export DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/{POSTGRES_DB} && \
  export CELERY_BROKER_URL=${REDIS_URL} && \
  export USE_DOCKER=yes && \
  export NPM_BIN_PATH=$(which npm) && \
  python manage.py tailwind install --no-input && \
  python manage.py tailwind build --no-input && \
  python manage.py collectstatic --no-input

ERROR:

#0 0.708 CommandError: 
#0 0.708 It looks like node.js and/or npm is not installed or cannot be found.
#0 0.708 
#0 0.708 Visit https://nodejs.org to download and install node.js for your system.
#0 0.708 
#0 0.708 If you have npm installed and still getting this error message, set NPM_BIN_PATH variable in settings.py to match path of NPM executable in your system.
#0 0.708 
#0 0.708 Example:
#0 0.708 NPM_BIN_PATH = "/usr/local/bin/npm"

SOLUTION: You have to use curl to download a setup script for node, from a non root directory:

ARG PYTHON_VERSION=3.10-slim-bullseye

# define an alias for the specfic python version used in this file.
FROM python:${PYTHON_VERSION} as python

# Python build stage
FROM python as python-build-stage

ARG BUILD_ENVIRONMENT=local

# Install apt packages
RUN apt-get update && apt-get install --no-install-recommends -y \
  # dependencies for building Python packages
  build-essential \
  # psycopg2 dependencies
  libpq-dev

# Requirements are installed here to ensure they will be cached.
COPY ./requirements .

# Create Python Dependency and Sub-Dependency Wheels.
RUN pip wheel --wheel-dir /usr/src/app/wheels  \
  -r ${BUILD_ENVIRONMENT}.txt


# Python 'run' stage
FROM python as python-run-stage

ARG BUILD_ENVIRONMENT=local
ARG APP_HOME=/app

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV BUILD_ENV ${BUILD_ENVIRONMENT}

WORKDIR ${APP_HOME}

RUN apt-get update && apt-get install -y curl 
RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash - &&\
   apt-get install -y nodejs

# Install required system dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \
  # psycopg2 dependencies
  libpq-dev \
  # Translations dependencies
  gettext \
  # cleaning up unused files
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*

# All absolute dir copies ignore workdir instruction. All relative dir copies are wrt to the workdir instruction
# copy python dependency wheels from python-build-stage
COPY --from=python-build-stage /usr/src/app/wheels  /wheels/

# use wheels to install python dependencies
RUN pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* \
	&& rm -rf /wheels/

COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r$//g' /entrypoint
RUN chmod +x /entrypoint

COPY ./compose/local/django/start /start
RUN sed -i 's/\r$//g' /start
RUN chmod +x /start

COPY ./compose/local/django/celery/worker/start /start-celeryworker
RUN sed -i 's/\r$//g' /start-celeryworker
RUN chmod +x /start-celeryworker

COPY ./compose/local/django/celery/beat/start /start-celerybeat
RUN sed -i 's/\r$//g' /start-celerybeat
RUN chmod +x /start-celerybeat

COPY ./compose/local/django/celery/flower/start /start-flower
RUN sed -i 's/\r$//g' /start-flower
RUN chmod +x /start-flower

# copy application code to WORKDIR
COPY . ${APP_HOME}

RUN export DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/{POSTGRES_DB} && \
  export CELERY_BROKER_URL=${REDIS_URL} && \
  export USE_DOCKER=yes && \
  export NPM_BIN_PATH=$(which npm) && \
  python manage.py makemigrations && \ 
 python manage.py migrate && \
  python manage.py tailwind install --no-input && \
  python manage.py tailwind build --no-input && \
  python manage.py collectstatic --no-input

ENTRYPOINT ["/entrypoint"]

@PositivPy
Copy link

However I am still left with

> theme@3.4.0 start
> npm run dev


> theme@3.4.0 dev
> cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w

node:events:491
      throw er; // Unhandled 'error' event
      ^

Error: spawn tailwindcss ENOENT
    at ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on ChildProcess instance at:
    at ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:483:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn tailwindcss',
  path: 'tailwindcss',
  spawnargs: [
    '--postcss',
    '-i',
    './src/styles.css',
    '-o',
    '../static/css/dist/styles.css',
    '-w'
  ]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants