Eliminate irrelevant rules when applying variants (#12113)

* Eliminate irrelevant rules when applying variants

* Update changelog
This commit is contained in:
Jordan Pittman 2023-09-29 16:31:43 -04:00
parent 17c7609419
commit 2c23b8da1c
4 changed files with 62 additions and 2 deletions

View File

@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Skip over classes inside `:not(…)` when nested in an at-rule ([#12105](https://github.com/tailwindlabs/tailwindcss/pull/12105))
- Update types to work with `Node16` module resolution ([#12097](https://github.com/tailwindlabs/tailwindcss/pull/12097))
- Dont crash when important and parent selectors are equal in `@apply` ([#12112](https://github.com/tailwindlabs/tailwindcss/pull/12112))
- Eliminate irrelevant rules when applying variants ([#12113](https://github.com/tailwindlabs/tailwindcss/pull/12113))
## [3.3.3] - 2023-07-13

View File

@ -820,10 +820,19 @@ function applyFinalFormat(match, { context, candidate }) {
}
try {
rule.selector = finalizeSelector(rule.selector, finalFormat, {
candidate: original,
let selector = finalizeSelector(rule.selector, finalFormat, {
candidate,
context,
})
// Finalize Selector determined that this candidate is irrelevant
// TODO: This elimination should happen earlier so this never happens
if (selector === null) {
rule.remove()
return
}
rule.selector = selector
} catch {
// If this selector is invalid we also want to skip it
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content

View File

@ -186,6 +186,13 @@ export function finalizeSelector(current, formats, { context, candidate, base })
// Remove extraneous selectors that do not include the base candidate
selector.each((sel) => eliminateIrrelevantSelectors(sel, base))
// If ffter eliminating irrelevant selectors, we end up with nothing
// Then the whole "rule" this is associated with does not need to exist
// We use `null` as a marker value for that case
if (selector.length === 0) {
return null
}
// If there are no formats that means there were no variants added to the candidate
// so we can just return the selector as-is
let formatAst = Array.isArray(formats)

View File

@ -1112,3 +1112,46 @@ crosscheck(({ stable, oxide, engine }) => {
expect(result.css).toMatchFormattedCss(css``)
})
})
test('Irrelevant rules are removed when applying variants', async () => {
let config = {
content: [
{
raw: html` <div class="md:w-full"></div> `,
},
],
corePlugins: { preflight: false },
plugins: [
function ({ addUtilities }) {
addUtilities({
'@supports (foo: bar)': {
// This doesn't contain `w-full` so it should not exist in the output
'.outer': { color: 'red' },
'.outer:is(.w-full)': { color: 'green' },
},
})
},
],
}
let input = css`
@tailwind utilities;
`
// We didn't find the hand class therefore
// nothing should be generated
let result = await run(input, config)
expect(result.css).toMatchFormattedCss(css`
@media (min-width: 768px) {
.md\:w-full {
width: 100%;
}
@supports (foo: bar) {
.outer.md\:w-full {
color: green;
}
}
}
`)
})