Skip to content

Commit be5d5c9

Browse files
Fix wildcard duplication issue (#7478)
This would be better as a symbol but the stringy-ness of class candidates is fairly well baked into assumptions across the codebase. Using `new String` with a well placed check seems to solve the problem.
1 parent db475be commit be5d5c9

File tree

6 files changed

+73
-5
lines changed

6 files changed

+73
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Remove opacity variables from `:visited` pseudo class ([#7458](https://github.com/tailwindlabs/tailwindcss/pull/7458))
1313
- Support arbitrary values + calc + theme with quotes ([#7462](https://github.com/tailwindlabs/tailwindcss/pull/7462))
14+
- Don't duplicate layer output when scanning content with variants + wildcards ([#7478](https://github.com/tailwindlabs/tailwindcss/pull/7478))
1415

1516
## [3.0.22] - 2022-02-11
1617

src/lib/expandTailwindAtRules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export default function expandTailwindAtRules(context) {
158158
// ---
159159

160160
// Find potential rules in changed files
161-
let candidates = new Set(['*'])
161+
let candidates = new Set([sharedState.NOT_ON_DEMAND])
162162
let seen = new Set()
163163

164164
env.DEBUG && console.time('Reading changed files')

src/lib/generateRules.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import isPlainObject from '../util/isPlainObject'
55
import prefixSelector from '../util/prefixSelector'
66
import { updateAllClasses } from '../util/pluginUtils'
77
import log from '../util/log'
8+
import * as sharedState from './sharedState'
89
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
910
import { asClass } from '../util/nameClass'
1011
import { normalize } from '../util/dataTypes'
@@ -382,6 +383,10 @@ function* resolveMatchedPlugins(classCandidate, context) {
382383
}
383384

384385
function splitWithSeparator(input, separator) {
386+
if (input === sharedState.NOT_ON_DEMAND) {
387+
return [sharedState.NOT_ON_DEMAND]
388+
}
389+
385390
return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
386391
}
387392

src/lib/setupContextUtils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function withIdentifiers(styles) {
138138

139139
// If this isn't "on-demandable", assign it a universal candidate to always include it.
140140
if (containsNonOnDemandableSelectors) {
141-
candidates.unshift('*')
141+
candidates.unshift(sharedState.NOT_ON_DEMAND)
142142
}
143143

144144
// However, it could be that it also contains "on-demandable" candidates.
@@ -163,8 +163,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
163163
}
164164

165165
function prefixIdentifier(identifier, options) {
166-
if (identifier === '*') {
167-
return '*'
166+
if (identifier === sharedState.NOT_ON_DEMAND) {
167+
return sharedState.NOT_ON_DEMAND
168168
}
169169

170170
if (!options.respectPrefix) {

src/lib/sharedState.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const env = {
55
export const contextMap = new Map()
66
export const configContextMap = new Map()
77
export const contextSourcesMap = new Map()
8+
export const NOT_ON_DEMAND = new String('*')
89

910
export function resolveDebug(debug) {
1011
if (debug === undefined) {

tests/basic-usage.test.js

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs'
22
import path from 'path'
33

4-
import { html, run, css } from './util/run'
4+
import { html, run, css, defaults } from './util/run'
55

66
test('basic usage', () => {
77
let config = {
@@ -188,3 +188,64 @@ it('can scan extremely long classes without crashing', () => {
188188
expect(result.css).toMatchFormattedCss(css``)
189189
})
190190
})
191+
192+
it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => {
193+
let config = {
194+
content: [{ raw: html`underline focus:*` }],
195+
corePlugins: { preflight: false },
196+
}
197+
198+
let input = css`
199+
@tailwind base;
200+
@tailwind components;
201+
@tailwind utilities;
202+
203+
* {
204+
color: red;
205+
}
206+
207+
.combined,
208+
* {
209+
text-align: center;
210+
}
211+
212+
@layer base {
213+
* {
214+
color: blue;
215+
}
216+
217+
.combined,
218+
* {
219+
color: red;
220+
}
221+
}
222+
`
223+
224+
return run(input, config).then((result) => {
225+
expect(result.css).toMatchFormattedCss(css`
226+
* {
227+
color: blue;
228+
}
229+
230+
.combined,
231+
* {
232+
color: red;
233+
}
234+
235+
${defaults}
236+
237+
.underline {
238+
text-decoration-line: underline;
239+
}
240+
241+
* {
242+
color: red;
243+
}
244+
245+
.combined,
246+
* {
247+
text-align: center;
248+
}
249+
`)
250+
})
251+
})

0 commit comments

Comments
 (0)