Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't duplicate layer output when scanning content with variants + wildcards #7478

Merged
merged 1 commit into from Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

## [3.0.22] - 2022-02-11

Expand Down
2 changes: 1 addition & 1 deletion src/lib/expandTailwindAtRules.js
Expand Up @@ -158,7 +158,7 @@ export default function expandTailwindAtRules(context) {
// ---

// Find potential rules in changed files
let candidates = new Set(['*'])
let candidates = new Set([sharedState.NOT_ON_DEMAND])
let seen = new Set()

env.DEBUG && console.time('Reading changed files')
Expand Down
5 changes: 5 additions & 0 deletions src/lib/generateRules.js
Expand Up @@ -5,6 +5,7 @@ import isPlainObject from '../util/isPlainObject'
import prefixSelector from '../util/prefixSelector'
import { updateAllClasses } from '../util/pluginUtils'
import log from '../util/log'
import * as sharedState from './sharedState'
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
import { asClass } from '../util/nameClass'
import { normalize } from '../util/dataTypes'
Expand Down Expand Up @@ -382,6 +383,10 @@ function* resolveMatchedPlugins(classCandidate, context) {
}

function splitWithSeparator(input, separator) {
if (input === sharedState.NOT_ON_DEMAND) {
return [sharedState.NOT_ON_DEMAND]
}

return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
}

Expand Down
6 changes: 3 additions & 3 deletions src/lib/setupContextUtils.js
Expand Up @@ -138,7 +138,7 @@ function withIdentifiers(styles) {

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

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

function prefixIdentifier(identifier, options) {
if (identifier === '*') {
return '*'
if (identifier === sharedState.NOT_ON_DEMAND) {
return sharedState.NOT_ON_DEMAND
}

if (!options.respectPrefix) {
Expand Down
1 change: 1 addition & 0 deletions src/lib/sharedState.js
Expand Up @@ -5,6 +5,7 @@ export const env = {
export const contextMap = new Map()
export const configContextMap = new Map()
export const contextSourcesMap = new Map()
export const NOT_ON_DEMAND = new String('*')

export function resolveDebug(debug) {
if (debug === undefined) {
Expand Down
63 changes: 62 additions & 1 deletion tests/basic-usage.test.js
@@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'

import { html, run, css } from './util/run'
import { html, run, css, defaults } from './util/run'

test('basic usage', () => {
let config = {
Expand Down Expand Up @@ -188,3 +188,64 @@ it('can scan extremely long classes without crashing', () => {
expect(result.css).toMatchFormattedCss(css``)
})
})

it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => {
let config = {
content: [{ raw: html`underline focus:*` }],
corePlugins: { preflight: false },
}

let input = css`
@tailwind base;
@tailwind components;
@tailwind utilities;

* {
color: red;
}

.combined,
* {
text-align: center;
}

@layer base {
* {
color: blue;
}

.combined,
* {
color: red;
}
}
`

return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
* {
color: blue;
}

.combined,
* {
color: red;
}

${defaults}

.underline {
text-decoration-line: underline;
}

* {
color: red;
}

.combined,
* {
text-align: center;
}
`)
})
})