Skip to content

Commit e292888

Browse files
Only emit utility/component variants when those layers exist (#7066)
1 parent 8293c2d commit e292888

File tree

4 files changed

+106
-9
lines changed

4 files changed

+106
-9
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Show warnings for invalid content config ([#7065](https://github.com/tailwindlabs/tailwindcss/pull/7065))
1313

14+
### Fixed
15+
16+
- Only emit utility/component variants when those layers exist ([#7066](https://github.com/tailwindlabs/tailwindcss/pull/7066))
17+
1418
## [3.0.13] - 2022-01-11
1519

1620
### Fixed

src/lib/expandTailwindAtRules.js

+23-8
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,6 @@ export default function expandTailwindAtRules(context) {
205205

206206
if (layerNodes.base) {
207207
layerNodes.base.before(cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source))
208-
}
209-
210-
if (layerNodes.base) {
211208
layerNodes.base.remove()
212209
}
213210

@@ -221,16 +218,34 @@ export default function expandTailwindAtRules(context) {
221218
layerNodes.utilities.remove()
222219
}
223220

221+
// We do post-filtering to not alter the emitted order of the variants
222+
const variantNodes = Array.from(screenNodes).filter((node) => {
223+
const parentLayer = node.raws.tailwind?.parentLayer
224+
225+
if (parentLayer === 'components') {
226+
return layerNodes.components !== null
227+
}
228+
229+
if (parentLayer === 'utilities') {
230+
return layerNodes.utilities !== null
231+
}
232+
233+
return true
234+
})
235+
224236
if (layerNodes.variants) {
225-
layerNodes.variants.before(cloneNodes([...screenNodes], layerNodes.variants.source))
237+
layerNodes.variants.before(cloneNodes(variantNodes, layerNodes.variants.source))
226238
layerNodes.variants.remove()
227-
} else {
228-
root.append(cloneNodes([...screenNodes], root.source))
239+
} else if (variantNodes.length > 0) {
240+
root.append(cloneNodes(variantNodes, root.source))
229241
}
230242

231243
// If we've got a utility layer and no utilities are generated there's likely something wrong
232-
// TODO: Detect utility variants only
233-
if (layerNodes.utilities && utilityNodes.size === 0 && screenNodes.size === 0) {
244+
const hasUtilityVariants = variantNodes.some(
245+
(node) => node.raws.tailwind?.parentLayer === 'utilities'
246+
)
247+
248+
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
234249
log.warn('content-problems', [
235250
'No utilities were generated there is likely a problem with the `content` key in the tailwind config. For more information see the documentation: https://tailwindcss.com/docs/content-configuration',
236251
])

src/lib/generateRules.js

+6
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ function applyVariant(variant, matches, context) {
216216
})
217217
}
218218

219+
// This tracks the originating layer for the variant
220+
// For example:
221+
// .sm:underline {} is a variant of something in the utilities layer
222+
// .sm:container {} is a variant of the container component
223+
clone.nodes[0].raws.tailwind = { parentLayer: meta.layer }
224+
219225
let withOffset = [
220226
{
221227
...meta,

tests/variants.test.js

+73-1
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 { run, css, html } from './util/run'
4+
import { run, css, html, defaults } from './util/run'
55

66
test('variants', () => {
77
let config = {
@@ -467,3 +467,75 @@ it('should be possible to use responsive modifiers that are defined with special
467467
`)
468468
})
469469
})
470+
471+
it('including just the base layer should not produce variants', () => {
472+
let config = {
473+
content: [{ raw: html`<div class="sm:container sm:underline"></div>` }],
474+
corePlugins: { preflight: false },
475+
}
476+
477+
return run('@tailwind base', config).then((result) => {
478+
return expect(result.css).toMatchFormattedCss(
479+
css`
480+
${defaults}
481+
`
482+
)
483+
})
484+
})
485+
486+
it('variants for components should not be produced in a file without a components layer', () => {
487+
let config = {
488+
content: [{ raw: html`<div class="sm:container sm:underline"></div>` }],
489+
}
490+
491+
return run('@tailwind utilities', config).then((result) => {
492+
return expect(result.css).toMatchFormattedCss(css`
493+
@media (min-width: 640px) {
494+
.sm\:underline {
495+
text-decoration-line: underline;
496+
}
497+
}
498+
`)
499+
})
500+
})
501+
502+
it('variants for utilities should not be produced in a file without a utilities layer', () => {
503+
let config = {
504+
content: [{ raw: html`<div class="sm:container sm:underline"></div>` }],
505+
}
506+
507+
return run('@tailwind components', config).then((result) => {
508+
return expect(result.css).toMatchFormattedCss(css`
509+
@media (min-width: 640px) {
510+
.sm\:container {
511+
width: 100%;
512+
}
513+
@media (min-width: 640px) {
514+
.sm\:container {
515+
max-width: 640px;
516+
}
517+
}
518+
@media (min-width: 768px) {
519+
.sm\:container {
520+
max-width: 768px;
521+
}
522+
}
523+
@media (min-width: 1024px) {
524+
.sm\:container {
525+
max-width: 1024px;
526+
}
527+
}
528+
@media (min-width: 1280px) {
529+
.sm\:container {
530+
max-width: 1280px;
531+
}
532+
}
533+
@media (min-width: 1536px) {
534+
.sm\:container {
535+
max-width: 1536px;
536+
}
537+
}
538+
}
539+
`)
540+
})
541+
})

0 commit comments

Comments
 (0)