Skip to content

Commit aecc852

Browse files
v3: Remove irrelevant utility rules when matching important classes (#19030)
Fixes #18678 When given a simple plugin like this: ```js export default { content: [{ raw: '!a' },], plugins: [ ({ addBase }) => addBase({ '@media (min-width: 1728px)': { '.a': { 'padding-top': '1rem !important' }, '.b': { 'padding-right': '1rem !important' }, } }), ], } ``` If this plugin saw the utility `!a` it would correctly modify both rules to eliminate any irrelevant classes. Unfortunately, in the case of the 2nd rule this meant it's left with an empty selector which is invalid. We now detect this case and remove the rule if that happens.
1 parent ba55a44 commit aecc852

File tree

3 files changed

+158
-1
lines changed

3 files changed

+158
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Fix `require.cache` error when loaded through a TypeScript file in Node 22.18+ ([#18665](https://github.com/tailwindlabs/tailwindcss/pull/18665))
1414
- Support `import.meta.resolve(…)` in configs for new enough Node.js versions ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938))
1515
- Allow using newer versions of `postcss-load-config` for better ESM and TypeScript PostCSS config support with the CLI ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938))
16+
- Remove irrelevant utility rules when matching important classes ([#19030](https://github.com/tailwindlabs/tailwindcss/pull/19030))
1617

1718
## [3.4.17] - 2024-12-17
1819

src/lib/generateRules.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,14 @@ function applyImportant(matches, classCandidate) {
143143
className === classCandidate ? `!${className}` : className
144144
)
145145

146-
r.selector = ast.toString()
146+
let newSelector = ast.toString()
147+
148+
if (newSelector.trim() === '') {
149+
r.remove()
150+
return
151+
}
152+
153+
r.selector = newSelector
147154

148155
r.walkDecls((d) => (d.important = true))
149156
})

tests/custom-plugins.test.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,3 +1914,152 @@ test('custom properties are not converted to kebab-case when added to base layer
19141914
expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`)
19151915
})
19161916
})
1917+
1918+
test('important candidates discard rules with irrelevant selectors', async () => {
1919+
let config = {
1920+
content: [{ raw: '!a1 !b1 !c1' }],
1921+
corePlugins: { preflight: false },
1922+
plugins: [
1923+
({ addBase }) => {
1924+
addBase({
1925+
'@media (min-width: 1728px)': {
1926+
'.a1': { 'padding-top': '1rem !important' },
1927+
'.a2': { 'padding-right': '1rem !important' },
1928+
},
1929+
})
1930+
1931+
addBase({
1932+
'@media (min-width: 1728px)': { '.b1': { 'padding-top': '1rem !important' } },
1933+
'@media (min-width: 1729px)': { '.b2': { 'padding-right': '1rem !important' } },
1934+
})
1935+
1936+
addBase({
1937+
'.c1': { '@media (min-width: 1728px)': { 'padding-top': '1rem !important' } },
1938+
'.c2': { '@media (min-width: 1728px)': { 'padding-right': '1rem !important' } },
1939+
})
1940+
},
1941+
],
1942+
}
1943+
1944+
let result = await run('@tailwind base', config)
1945+
1946+
expect(result.css).toMatchInlineSnapshot(`
1947+
"*, ::before, ::after {
1948+
--tw-border-spacing-x: 0;
1949+
--tw-border-spacing-y: 0;
1950+
--tw-translate-x: 0;
1951+
--tw-translate-y: 0;
1952+
--tw-rotate: 0;
1953+
--tw-skew-x: 0;
1954+
--tw-skew-y: 0;
1955+
--tw-scale-x: 1;
1956+
--tw-scale-y: 1;
1957+
--tw-pan-x: ;
1958+
--tw-pan-y: ;
1959+
--tw-pinch-zoom: ;
1960+
--tw-scroll-snap-strictness: proximity;
1961+
--tw-gradient-from-position: ;
1962+
--tw-gradient-via-position: ;
1963+
--tw-gradient-to-position: ;
1964+
--tw-ordinal: ;
1965+
--tw-slashed-zero: ;
1966+
--tw-numeric-figure: ;
1967+
--tw-numeric-spacing: ;
1968+
--tw-numeric-fraction: ;
1969+
--tw-ring-inset: ;
1970+
--tw-ring-offset-width: 0px;
1971+
--tw-ring-offset-color: #fff;
1972+
--tw-ring-color: rgb(59 130 246 / 0.5);
1973+
--tw-ring-offset-shadow: 0 0 #0000;
1974+
--tw-ring-shadow: 0 0 #0000;
1975+
--tw-shadow: 0 0 #0000;
1976+
--tw-shadow-colored: 0 0 #0000;
1977+
--tw-blur: ;
1978+
--tw-brightness: ;
1979+
--tw-contrast: ;
1980+
--tw-grayscale: ;
1981+
--tw-hue-rotate: ;
1982+
--tw-invert: ;
1983+
--tw-saturate: ;
1984+
--tw-sepia: ;
1985+
--tw-drop-shadow: ;
1986+
--tw-backdrop-blur: ;
1987+
--tw-backdrop-brightness: ;
1988+
--tw-backdrop-contrast: ;
1989+
--tw-backdrop-grayscale: ;
1990+
--tw-backdrop-hue-rotate: ;
1991+
--tw-backdrop-invert: ;
1992+
--tw-backdrop-opacity: ;
1993+
--tw-backdrop-saturate: ;
1994+
--tw-backdrop-sepia: ;
1995+
--tw-contain-size: ;
1996+
--tw-contain-layout: ;
1997+
--tw-contain-paint: ;
1998+
--tw-contain-style:
1999+
}
2000+
::backdrop {
2001+
--tw-border-spacing-x: 0;
2002+
--tw-border-spacing-y: 0;
2003+
--tw-translate-x: 0;
2004+
--tw-translate-y: 0;
2005+
--tw-rotate: 0;
2006+
--tw-skew-x: 0;
2007+
--tw-skew-y: 0;
2008+
--tw-scale-x: 1;
2009+
--tw-scale-y: 1;
2010+
--tw-pan-x: ;
2011+
--tw-pan-y: ;
2012+
--tw-pinch-zoom: ;
2013+
--tw-scroll-snap-strictness: proximity;
2014+
--tw-gradient-from-position: ;
2015+
--tw-gradient-via-position: ;
2016+
--tw-gradient-to-position: ;
2017+
--tw-ordinal: ;
2018+
--tw-slashed-zero: ;
2019+
--tw-numeric-figure: ;
2020+
--tw-numeric-spacing: ;
2021+
--tw-numeric-fraction: ;
2022+
--tw-ring-inset: ;
2023+
--tw-ring-offset-width: 0px;
2024+
--tw-ring-offset-color: #fff;
2025+
--tw-ring-color: rgb(59 130 246 / 0.5);
2026+
--tw-ring-offset-shadow: 0 0 #0000;
2027+
--tw-ring-shadow: 0 0 #0000;
2028+
--tw-shadow: 0 0 #0000;
2029+
--tw-shadow-colored: 0 0 #0000;
2030+
--tw-blur: ;
2031+
--tw-brightness: ;
2032+
--tw-contrast: ;
2033+
--tw-grayscale: ;
2034+
--tw-hue-rotate: ;
2035+
--tw-invert: ;
2036+
--tw-saturate: ;
2037+
--tw-sepia: ;
2038+
--tw-drop-shadow: ;
2039+
--tw-backdrop-blur: ;
2040+
--tw-backdrop-brightness: ;
2041+
--tw-backdrop-contrast: ;
2042+
--tw-backdrop-grayscale: ;
2043+
--tw-backdrop-hue-rotate: ;
2044+
--tw-backdrop-invert: ;
2045+
--tw-backdrop-opacity: ;
2046+
--tw-backdrop-saturate: ;
2047+
--tw-backdrop-sepia: ;
2048+
--tw-contain-size: ;
2049+
--tw-contain-layout: ;
2050+
--tw-contain-paint: ;
2051+
--tw-contain-style:
2052+
}
2053+
@media (min-width: 1728px) {
2054+
.\\!a1 {
2055+
padding-top: 1rem !important
2056+
}
2057+
.\\!b1 {
2058+
padding-top: 1rem !important
2059+
}
2060+
.\\!c1 {
2061+
padding-top: 1rem !important
2062+
}
2063+
}"
2064+
`)
2065+
})

0 commit comments

Comments
 (0)