Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### 🎯 New Features
- **Configurable minification**: New `TAILWIND_CLI_AUTOMATIC_MINIFY` setting and `--minify` / `--no-minify` flag on `tailwind build` for projects whose asset pipelines already minify CSS. Defaults preserve existing behavior.

### 🛠️ Developer Experience
- **Gitignore cleanup**: Trimmed `.gitignore` to project-relevant entries only

Expand Down
8 changes: 8 additions & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ In case you want to use the new behaviour, it is highly recommended to also set

Enable or disable the automatic downloading of the official CLI to your machine.

### TAILWIND_CLI_AUTOMATIC_MINIFY

**Default**: `True`

Controls whether `python manage.py tailwind build` passes `--minify` to the Tailwind CLI. Set to `False` if your asset pipeline already minifies CSS (for example when using `django-compressor` or a CDN transform) so you don't minify twice.

This setting only changes the default; the `build` command also accepts an explicit `--minify` / `--no-minify` flag which takes precedence.

### TAILWIND_CLI_SRC_REPO

**Default**: `"tailwindlabs/tailwindcss"`
Expand Down
8 changes: 5 additions & 3 deletions src/django_tailwind_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,18 @@ def get_watch_cmd(self, entry: CSSEntry) -> list[str]:
"--watch",
]

def get_build_cmd(self, entry: CSSEntry) -> list[str]:
def get_build_cmd(self, entry: CSSEntry, *, minify: bool = True) -> list[str]:
"""Generate build command for a specific CSS entry."""
return [
cmd = [
str(self.cli_path),
"--input",
str(entry.src_css),
"--output",
str(entry.dist_css),
"--minify",
]
if minify:
cmd.append("--minify")
return cmd

@property
def watch_cmd(self) -> list[str]:
Expand Down
17 changes: 14 additions & 3 deletions src/django_tailwind_cli/management/commands/tailwind.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,16 @@ def build(
"-v",
help="Show detailed build information and diagnostics.",
),
minify: bool | None = typer.Option(
None,
"--minify/--no-minify",
help=(
"Produce a minified stylesheet. Defaults to the value of the "
"TAILWIND_CLI_AUTOMATIC_MINIFY Django setting (True if unset)."
),
),
) -> None:
"""Build minified production-ready CSS file(s).
"""Build production-ready CSS file(s).

This command processes your Tailwind CSS input file(s) and generates optimized
production CSS file(s) with only the styles actually used in your templates.
Expand Down Expand Up @@ -215,6 +223,9 @@ def build(
start_time = time.time()
config = get_config()

if minify is None:
minify = getattr(settings, "TAILWIND_CLI_AUTOMATIC_MINIFY", True)

if verbose:
typer.secho("🏗️ Starting Tailwind CSS build process...", fg=typer.colors.CYAN)
typer.secho(f" • CSS entries: {len(config.css_entries)}", fg=typer.colors.BLUE)
Expand Down Expand Up @@ -244,12 +255,12 @@ def build(
continue

if verbose:
build_cmd = config.get_build_cmd(entry)
build_cmd = config.get_build_cmd(entry, minify=minify)
typer.secho(f"⚡ [{entry.name}] Executing Tailwind CSS build command...", fg=typer.colors.CYAN)
typer.secho(f" • Command: {' '.join(build_cmd)}", fg=typer.colors.BLUE)

_execute_tailwind_command(
config.get_build_cmd(entry),
config.get_build_cmd(entry, minify=minify),
success_message=f"Built production stylesheet '{entry.dist_css}'.",
error_message=f"Failed to build production stylesheet '{entry.name}'",
verbose=verbose,
Expand Down
9 changes: 9 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,15 @@ def test_css_map_get_build_cmd(settings: SettingsWrapper):
assert str(entry.dist_css) in cmd


def test_get_build_cmd_without_minify(settings: SettingsWrapper):
settings.TAILWIND_CLI_CSS_MAP = [("admin.css", "admin.output.css")]
c = get_config()
cmd = c.get_build_cmd(c.css_entries[0], minify=False)
assert "--minify" not in cmd
assert "--input" in cmd
assert "--output" in cmd


def test_css_map_get_watch_cmd(settings: SettingsWrapper):
settings.TAILWIND_CLI_CSS_MAP = [
("admin.css", "admin.output.css"),
Expand Down
39 changes: 39 additions & 0 deletions tests/test_management_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,45 @@ def test_build_subprocess_calls(self):
# Verify subprocess.run was called
assert self.mock_subprocess_run.call_count >= 1

@pytest.mark.timeout(5)
def test_build_minifies_by_default(self):
"""Build command includes --minify by default."""
call_command("tailwind", "build")
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
assert "--minify" in cmd

@pytest.mark.timeout(5)
def test_build_respects_automatic_minify_setting_true(self, settings: LazySettings):
"""TAILWIND_CLI_AUTOMATIC_MINIFY=True explicitly set still minifies."""
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = True
call_command("tailwind", "build")
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
assert "--minify" in cmd

@pytest.mark.timeout(5)
def test_build_respects_automatic_minify_setting(self, settings: LazySettings):
"""TAILWIND_CLI_AUTOMATIC_MINIFY=False disables minification."""
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = False
call_command("tailwind", "build")
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
assert "--minify" not in cmd

@pytest.mark.timeout(5)
def test_build_no_minify_flag_overrides_setting(self, settings: LazySettings):
"""--no-minify CLI flag overrides the setting."""
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = True
call_command("tailwind", "build", "--no-minify")
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
assert "--minify" not in cmd

@pytest.mark.timeout(5)
def test_build_minify_flag_overrides_setting(self, settings: LazySettings):
"""--minify CLI flag overrides TAILWIND_CLI_AUTOMATIC_MINIFY=False."""
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = False
call_command("tailwind", "build", "--minify")
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
assert "--minify" in cmd

@pytest.mark.timeout(5)
def test_build_with_keyboard_interrupt(self, capsys: CaptureFixture[str]):
"""Test build command handling of KeyboardInterrupt."""
Expand Down
Loading