Skip to content

Django integration #20

@JakobLien

Description

@JakobLien

Hi! As I lack access to create branches or pull requests, this enhancement comes as an issue, which I invite you to do as you wish with.

I really like this package, and have been using it in my django hobby project. However, as I have not one but two tailwindcss files to generate, to work on the css of the project I must run three commands simultaneously. Therefore I would have liked to integrate this better with django's StatReloader, the default one to reload a django project. Having now gotten it working as I wanted, I would like to share this with other people, preferably by adding the following to the bottom of this project's readme. If you (understandably) feel that it makes the readme way to cluttered, I would suggest adding it to a new markdown file in the repo, and linking to it from the main one. My suggestion to add is as follows:

Django integration

If you happen to be using django, and would like tailwindcss to be automatically run when saving relevant files using the StatReloader, the following code is a working example of this on django 5.2.11. It works by overriding the base runserver command by adding it as a management command, and adding a --tw argument to it. This lets you only need to run one command to work on the css of your webiste, which is quite convenient.

from pathlib import Path
import subprocess
import re

from django.conf import settings
from django.contrib.staticfiles.management.commands.runserver import Command as RunServerCommand
from django.utils import autoreload
from django.utils.autoreload import autoreload_started

class Command(RunServerCommand):
    help = "Run Django development server with Tailwind CSS watch mode"

    def add_arguments(self, parser):
        super().add_arguments(parser)
        parser.add_argument(
            '--tw',
            action='store_true',
            help='Automatically update styles.css when source files change',
        )

    def repoRoot(self):
        return Path(__file__).parent.parent.parent.parent

    def runCommandOnChange(self, regexPath, command, preventReload=False):
        def callback(sender: autoreload.StatReloader, file_path, **kwargs):
            pathFromRepoRoot = str(file_path).replace(str(self.repoRoot()), '')
            if re.fullmatch(regexPath, pathFromRepoRoot):
                print(file_path, 'changed, running:\n', command)
                subprocess.Popen(command.split(' '))
                return preventReload
        autoreload.file_changed.connect(callback)

    def handle(self, *args, **options):
        if settings.DEBUG and options['tw']:
            def watchExtra(sender: autoreload.StatReloader, **kwargs):
               # Add extra files that django otherwise wouldn't watch here,
               # in general, any non-python files besides templates must be added here 
               sender.extra_files.add(self.repoRoot() / 'mysite/static/mysite/inputStyles.css')
            autoreload_started.connect(watchExtra)

            self.runCommandOnChange(
                r'/mysite/(templates/.*|static/mysite/inputStyles.css)',
                'tailwindcss --cwd mysite -i static/mysite/inputStyles.css -o static/mysite/styles.css --minify',
                preventReload=True
            )

        super().handle(*args, **options)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions