From 5c76b4945f83ba46e63edd6885f344356fde6e20 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Thu, 20 Mar 2025 12:44:38 +0100 Subject: [PATCH] Ensure that the CSS file rebuilds if a new CSS variable is used from templates --- CHANGELOG.md | 1 + integrations/cli/index.test.ts | 6 +++--- packages/tailwindcss/src/index.ts | 9 ++++++--- packages/tailwindcss/src/theme.ts | 6 ++++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a333cb74d6cb..6dd83467d39b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix class extraction followed by `(` in Slim ([#17278](https://github.com/tailwindlabs/tailwindcss/pull/17278)) - Export `PluginUtils` from `tailwindcss/plugin` for compatibility with v3 ([#17299](https://github.com/tailwindlabs/tailwindcss/pull/17299)) - Increase Standalone hardware compatibility on macOS x64 builds ([#17267](https://github.com/tailwindlabs/tailwindcss/pull/17267)) +- Ensure that the CSS file rebuilds if a new CSS variable is used from templates ([#17301](https://github.com/tailwindlabs/tailwindcss/pull/17301)) ## [4.0.14] - 2025-03-13 diff --git a/integrations/cli/index.test.ts b/integrations/cli/index.test.ts index bb9624c20710..1e1fca38b324 100644 --- a/integrations/cli/index.test.ts +++ b/integrations/cli/index.test.ts @@ -1303,11 +1303,11 @@ test( `, ) - fs.expectFileToContain( + // prettier-ignore + await fs.expectFileToContain( './dist/out.css', css` - :root, - :host { + :root, :host { --color-blue-500: blue; } `, diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index ddcd17ae6565..ebf4b3875baf 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -696,6 +696,7 @@ export async function compileAst( } let didChange = defaultDidChange + let didAddExternalVariable = false defaultDidChange = false // Add all new candidates unless we know that they are invalid. @@ -703,11 +704,13 @@ export async function compileAst( for (let candidate of newRawCandidates) { if (!designSystem.invalidCandidates.has(candidate)) { if (candidate[0] === '-' && candidate[1] === '-') { - designSystem.theme.markUsedVariable(candidate) + let didMarkVariableAsUsed = designSystem.theme.markUsedVariable(candidate) + didChange ||= didMarkVariableAsUsed + didAddExternalVariable ||= didMarkVariableAsUsed } else { allValidCandidates.add(candidate) + didChange ||= allValidCandidates.size !== prevSize } - didChange ||= allValidCandidates.size !== prevSize } } @@ -725,7 +728,7 @@ export async function compileAst( // If no new ast nodes were generated, then we can return the original // CSS. This currently assumes that we only add new ast nodes and never // remove any. - if (previousAstNodeCount === newNodes.length) { + if (!didAddExternalVariable && previousAstNodeCount === newNodes.length) { compiled ??= optimizeAst(ast, designSystem) return compiled } diff --git a/packages/tailwindcss/src/theme.ts b/packages/tailwindcss/src/theme.ts index d5fca3b02d3d..34e2a9c5d2ce 100644 --- a/packages/tailwindcss/src/theme.ts +++ b/packages/tailwindcss/src/theme.ts @@ -193,11 +193,13 @@ export class Theme { return `var(${escape(this.prefixKey(themeKey))}${fallback ? `, ${fallback}` : ''})` } - markUsedVariable(themeKey: string) { + markUsedVariable(themeKey: string): boolean { let key = unescape(this.#unprefixKey(themeKey)) let value = this.values.get(key) - if (!value) return + if (!value) return false + let isUsed = value.options & ThemeOptions.USED value.options |= ThemeOptions.USED + return !isUsed } resolve(candidateValue: string | null, themeKeys: ThemeKey[]): string | null {