Skip to content

Commit

Permalink
Eliminate irrelevant rules when applying variants (#12113)
Browse files Browse the repository at this point in the history
* Eliminate irrelevant rules when applying variants

* Update changelog
  • Loading branch information
thecrypticace authored Sep 29, 2023
1 parent 457d2b1 commit 5542340
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
- Don’t 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))

### Added

Expand Down
11 changes: 10 additions & 1 deletion src/lib/generateRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -815,10 +815,19 @@ function applyFinalFormat(match, { context, candidate }) {
}

try {
rule.selector = finalizeSelector(rule.selector, finalFormat, {
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
Expand Down
7 changes: 7 additions & 0 deletions src/util/formatVariantSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 43 additions & 0 deletions tests/basic-usage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -792,3 +792,46 @@ test('Skips classes inside :not() when nested inside an at-rule', async () => {

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;
}
}
}
`)
})

0 comments on commit 5542340

Please sign in to comment.