django-tailwind
django-tailwind copied to clipboard
Incorporating django-tailwind into existing dockerized cookiecutter-django project?
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"]
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.
You'll have to add
tailwindtoINSTALLED_APPSin 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.
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: https://github.com/timonweb/django-tailwind/blob/37b81f631edddac04844413bb5635a1c73e5af30/example/Dockerfile#L8
- Run
manage.py tailwind installto install npm packages: https://github.com/timonweb/django-tailwind/blob/37b81f631edddac04844413bb5635a1c73e5af30/example/Dockerfile#L29 - Build the tailwind assets and collect Django static files (I'm surprised that
collectstaticis not already part of the cookiecutter Dockerfile): https://github.com/timonweb/django-tailwind/blob/37b81f631edddac04844413bb5635a1c73e5af30/example/Dockerfile#L30-L31
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): https://github.com/timonweb/django-tailwind/blob/37b81f631edddac04844413bb5635a1c73e5af30/example/docker-compose.yml#L17-L22
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.
@BenAkko Looks like I've missed a line. The example Dockerfile configures the official nodesource package repositories: https://github.com/timonweb/django-tailwind/blob/37b81f631edddac04844413bb5635a1c73e5af30/example/Dockerfile#L7-L8
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.
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"]
However I am still left with
> [email protected] start
> npm run dev
> [email protected] 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'
]
}