Skip to content

Commit 7c64448

Browse files
authored
Allow generation of unminified CSS file (#195)
* Allow disabling minification * Add uv lock updates Automatically added from running `just bootstrap` * Add unit test for get_build_cmd with minify=False
1 parent 62b93b6 commit 7c64448

7 files changed

Lines changed: 438 additions & 270 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
### 🎯 New Features
6+
- **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.
7+
58
### 🛠️ Developer Experience
69
- **Gitignore cleanup**: Trimmed `.gitignore` to project-relevant entries only
710

docs/settings.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ In case you want to use the new behaviour, it is highly recommended to also set
4242

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

45+
### TAILWIND_CLI_AUTOMATIC_MINIFY
46+
47+
**Default**: `True`
48+
49+
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.
50+
51+
This setting only changes the default; the `build` command also accepts an explicit `--minify` / `--no-minify` flag which takes precedence.
52+
4553
### TAILWIND_CLI_SRC_REPO
4654

4755
**Default**: `"tailwindlabs/tailwindcss"`

src/django_tailwind_cli/config.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,18 @@ def get_watch_cmd(self, entry: CSSEntry) -> list[str]:
149149
"--watch",
150150
]
151151

152-
def get_build_cmd(self, entry: CSSEntry) -> list[str]:
152+
def get_build_cmd(self, entry: CSSEntry, *, minify: bool = True) -> list[str]:
153153
"""Generate build command for a specific CSS entry."""
154-
return [
154+
cmd = [
155155
str(self.cli_path),
156156
"--input",
157157
str(entry.src_css),
158158
"--output",
159159
str(entry.dist_css),
160-
"--minify",
161160
]
161+
if minify:
162+
cmd.append("--minify")
163+
return cmd
162164

163165
@property
164166
def watch_cmd(self) -> list[str]:

src/django_tailwind_cli/management/commands/tailwind.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,16 @@ def build(
181181
"-v",
182182
help="Show detailed build information and diagnostics.",
183183
),
184+
minify: bool | None = typer.Option(
185+
None,
186+
"--minify/--no-minify",
187+
help=(
188+
"Produce a minified stylesheet. Defaults to the value of the "
189+
"TAILWIND_CLI_AUTOMATIC_MINIFY Django setting (True if unset)."
190+
),
191+
),
184192
) -> None:
185-
"""Build minified production-ready CSS file(s).
193+
"""Build production-ready CSS file(s).
186194
187195
This command processes your Tailwind CSS input file(s) and generates optimized
188196
production CSS file(s) with only the styles actually used in your templates.
@@ -215,6 +223,9 @@ def build(
215223
start_time = time.time()
216224
config = get_config()
217225

226+
if minify is None:
227+
minify = getattr(settings, "TAILWIND_CLI_AUTOMATIC_MINIFY", True)
228+
218229
if verbose:
219230
typer.secho("🏗️ Starting Tailwind CSS build process...", fg=typer.colors.CYAN)
220231
typer.secho(f" • CSS entries: {len(config.css_entries)}", fg=typer.colors.BLUE)
@@ -244,12 +255,12 @@ def build(
244255
continue
245256

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

251262
_execute_tailwind_command(
252-
config.get_build_cmd(entry),
263+
config.get_build_cmd(entry, minify=minify),
253264
success_message=f"Built production stylesheet '{entry.dist_css}'.",
254265
error_message=f"Failed to build production stylesheet '{entry.name}'",
255266
verbose=verbose,

tests/test_config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,15 @@ def test_css_map_get_build_cmd(settings: SettingsWrapper):
431431
assert str(entry.dist_css) in cmd
432432

433433

434+
def test_get_build_cmd_without_minify(settings: SettingsWrapper):
435+
settings.TAILWIND_CLI_CSS_MAP = [("admin.css", "admin.output.css")]
436+
c = get_config()
437+
cmd = c.get_build_cmd(c.css_entries[0], minify=False)
438+
assert "--minify" not in cmd
439+
assert "--input" in cmd
440+
assert "--output" in cmd
441+
442+
434443
def test_css_map_get_watch_cmd(settings: SettingsWrapper):
435444
settings.TAILWIND_CLI_CSS_MAP = [
436445
("admin.css", "admin.output.css"),

tests/test_management_commands.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,45 @@ def test_build_subprocess_calls(self):
134134
# Verify subprocess.run was called
135135
assert self.mock_subprocess_run.call_count >= 1
136136

137+
@pytest.mark.timeout(5)
138+
def test_build_minifies_by_default(self):
139+
"""Build command includes --minify by default."""
140+
call_command("tailwind", "build")
141+
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
142+
assert "--minify" in cmd
143+
144+
@pytest.mark.timeout(5)
145+
def test_build_respects_automatic_minify_setting_true(self, settings: LazySettings):
146+
"""TAILWIND_CLI_AUTOMATIC_MINIFY=True explicitly set still minifies."""
147+
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = True
148+
call_command("tailwind", "build")
149+
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
150+
assert "--minify" in cmd
151+
152+
@pytest.mark.timeout(5)
153+
def test_build_respects_automatic_minify_setting(self, settings: LazySettings):
154+
"""TAILWIND_CLI_AUTOMATIC_MINIFY=False disables minification."""
155+
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = False
156+
call_command("tailwind", "build")
157+
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
158+
assert "--minify" not in cmd
159+
160+
@pytest.mark.timeout(5)
161+
def test_build_no_minify_flag_overrides_setting(self, settings: LazySettings):
162+
"""--no-minify CLI flag overrides the setting."""
163+
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = True
164+
call_command("tailwind", "build", "--no-minify")
165+
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
166+
assert "--minify" not in cmd
167+
168+
@pytest.mark.timeout(5)
169+
def test_build_minify_flag_overrides_setting(self, settings: LazySettings):
170+
"""--minify CLI flag overrides TAILWIND_CLI_AUTOMATIC_MINIFY=False."""
171+
settings.TAILWIND_CLI_AUTOMATIC_MINIFY = False
172+
call_command("tailwind", "build", "--minify")
173+
cmd = self.mock_subprocess_run.call_args_list[-1].args[0]
174+
assert "--minify" in cmd
175+
137176
@pytest.mark.timeout(5)
138177
def test_build_with_keyboard_interrupt(self, capsys: CaptureFixture[str]):
139178
"""Test build command handling of KeyboardInterrupt."""

0 commit comments

Comments
 (0)