Skip to content

Commit b69e46c

Browse files
committed
Rename buckets to layers, handle copying layer information to responsive variants
1 parent f25b092 commit b69e46c

File tree

4 files changed

+96
-39
lines changed

4 files changed

+96
-39
lines changed

src/lib/purgeUnusedStyles.js

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@ import chalk from 'chalk'
55
import { log } from '../cli/utils'
66
import * as emoji from '../cli/emoji'
77

8+
function convertLayersToControlComments(css) {
9+
css.walkAtRules('layer', atRule => {
10+
const layer = atRule.params
11+
atRule.before(postcss.comment({ text: `tailwind start ${layer}` }))
12+
atRule.before(atRule.nodes)
13+
atRule.before(postcss.comment({ text: `tailwind end ${layer}` }))
14+
atRule.remove()
15+
})
16+
}
17+
18+
function convertControlCommentsToPurgeIgnoreComments(config) {
19+
return function(css) {
20+
const mode = _.get(config, 'purge.mode', 'conservative')
21+
22+
if (mode === 'conservative') {
23+
css.prepend(postcss.comment({ text: 'purgecss start ignore' }))
24+
css.append(postcss.comment({ text: 'purgecss end ignore' }))
25+
26+
css.walkComments(comment => {
27+
switch (comment.text.trim()) {
28+
case 'tailwind start utilities':
29+
comment.text = 'purgecss end ignore'
30+
break
31+
case 'tailwind end utilities':
32+
comment.text = 'purgecss start ignore'
33+
break
34+
default:
35+
break
36+
}
37+
})
38+
}
39+
}
40+
}
41+
842
function removeTailwindComments(css) {
943
css.walkComments(comment => {
1044
switch (comment.text.trim()) {
@@ -28,7 +62,7 @@ export default function purgeUnusedUtilities(config) {
2862
)
2963

3064
if (!purgeEnabled) {
31-
return removeTailwindComments
65+
return postcss([convertLayersToControlComments, removeTailwindComments])
3266
}
3367

3468
// Skip if `purge: []` since that's part of the default config
@@ -52,29 +86,9 @@ export default function purgeUnusedUtilities(config) {
5286
}
5387

5488
return postcss([
55-
function(css) {
56-
const mode = _.get(config, 'purge.mode', 'conservative')
57-
58-
if (mode === 'conservative') {
59-
css.prepend(postcss.comment({ text: 'purgecss start ignore' }))
60-
css.append(postcss.comment({ text: 'purgecss end ignore' }))
61-
62-
css.walkComments(comment => {
63-
switch (comment.text.trim()) {
64-
case 'tailwind start utilities':
65-
comment.text = 'purgecss end ignore'
66-
break
67-
case 'tailwind end utilities':
68-
comment.text = 'purgecss start ignore'
69-
break
70-
default:
71-
break
72-
}
73-
})
74-
}
75-
76-
removeTailwindComments(css)
77-
},
89+
convertLayersToControlComments,
90+
convertControlCommentsToPurgeIgnoreComments(config),
91+
removeTailwindComments,
7892
purgecss({
7993
content: Array.isArray(config.purge) ? config.purge : config.purge.content,
8094
defaultExtractor: content => {

src/lib/substituteResponsiveAtRules.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,51 @@ import cloneNodes from '../util/cloneNodes'
44
import buildMediaQuery from '../util/buildMediaQuery'
55
import buildSelectorVariant from '../util/buildSelectorVariant'
66

7+
function isLayer(node) {
8+
if (Array.isArray(node)) {
9+
return node.length === 1 && isLayer(node[0])
10+
}
11+
return node.type === 'atrule' && node.name === 'layer'
12+
}
13+
14+
function layerNodes(nodes) {
15+
return isLayer(nodes) ? nodes[0].nodes : nodes
16+
}
17+
718
export default function(config) {
819
return function(css) {
20+
// Wrap any `responsive` rules with a copy of their parent `layer` to
21+
// ensure the layer isn't lost when copying to the `screens` location.
22+
css.walkAtRules('layer', layerAtRule => {
23+
const layer = layerAtRule.params
24+
layerAtRule.walkAtRules('responsive', responsiveAtRule => {
25+
const nestedlayerAtRule = postcss.atRule({
26+
name: 'layer',
27+
params: layer,
28+
})
29+
nestedlayerAtRule.prepend(responsiveAtRule.nodes)
30+
responsiveAtRule.removeAll()
31+
responsiveAtRule.prepend(nestedlayerAtRule)
32+
})
33+
})
34+
35+
// Find any `responsive` rules with no parent `layer` (these only come
36+
// from the user's CSS, Tailwind never generates things this way itself)
37+
// and wrap them with a default `layer` of `utilities`.
38+
css.walkAtRules('responsive', responsiveAtRule => {
39+
const [node] = responsiveAtRule.nodes
40+
if (node.type === 'atrule' && node.name === 'layer') {
41+
return
42+
}
43+
const nestedlayerAtRule = postcss.atRule({
44+
name: 'layer',
45+
params: 'utilities',
46+
})
47+
nestedlayerAtRule.prepend(responsiveAtRule.nodes)
48+
responsiveAtRule.removeAll()
49+
responsiveAtRule.prepend(nestedlayerAtRule)
50+
})
51+
952
const {
1053
theme: { screens },
1154
separator,
@@ -16,7 +59,16 @@ export default function(config) {
1659
css.walkAtRules('responsive', atRule => {
1760
const nodes = atRule.nodes
1861
responsiveRules.append(...cloneNodes(nodes))
19-
atRule.before(nodes)
62+
63+
// If the parent is already a `layer` (this is true for anything coming from
64+
// a plugin, including core plugins) we don't want to create a double nested
65+
// layer, so only insert the layer children. If there is no parent layer,
66+
// preserve the layer information when inserting the nodes.
67+
if (isLayer(atRule.parent)) {
68+
atRule.before(layerNodes(nodes))
69+
} else {
70+
atRule.before(nodes)
71+
}
2072
atRule.remove()
2173
})
2274

src/processTailwindFeatures.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,6 @@ export default function(getConfig) {
2424
substituteResponsiveAtRules(config),
2525
substituteScreenAtRules(config),
2626
substituteClassApplyAtRules(config, processedPlugins.utilities),
27-
function(css) {
28-
css.walkAtRules('bucket', atRule => {
29-
const bucket = atRule.params
30-
atRule.before(postcss.comment({ text: `tailwind start ${bucket}` }))
31-
atRule.before(atRule.nodes)
32-
atRule.before(postcss.comment({ text: `tailwind end ${bucket}` }))
33-
atRule.remove()
34-
})
35-
},
3627
purgeUnusedStyles(config),
3728
]).process(css, { from: _.get(css, 'source.input.file') })
3829
}

src/util/processPlugins.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ function containsClass(value) {
2828
}).transformSync(value)
2929
}
3030

31-
function wrapWithBucket(rules, bucket) {
31+
function wrapWithLayer(rules, layer) {
3232
return postcss
3333
.atRule({
34-
name: 'bucket',
35-
params: bucket,
34+
name: 'layer',
35+
params: layer,
3636
})
3737
.append(cloneNodes(Array.isArray(rules) ? rules : [rules]))
3838
}
@@ -119,7 +119,7 @@ export default function(plugins, config) {
119119
})
120120

121121
pluginUtilities.push(
122-
wrapWithVariants(wrapWithBucket(styles.nodes, 'utilities'), options.variants)
122+
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'utilities')
123123
)
124124
},
125125
addComponents: (components, options) => {
@@ -138,7 +138,7 @@ export default function(plugins, config) {
138138
})
139139

140140
pluginComponents.push(
141-
wrapWithVariants(wrapWithBucket(styles.nodes, 'components'), options.variants)
141+
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'components')
142142
)
143143
},
144144
addBase: baseStyles => {

0 commit comments

Comments
 (0)