Skip to content

Commit a891867

Browse files
Fix consecutive builds with at apply producing different CSS (#6999)
* Partition at rules before building context * remove unnecessary logic * Update changelog Co-authored-by: Robin Malfait <[email protected]>
1 parent 3a13cfc commit a891867

5 files changed

+125
-75
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Fix consecutive builds with at apply producing different CSS ([#6999](https://github.com/tailwindlabs/tailwindcss/pull/6999))
1113

1214
## [3.0.12] - 2022-01-07
1315

src/lib/partitionApplyAtRules.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
function partitionRules(root) {
2+
if (!root.walkAtRules) return
3+
4+
let applyParents = new Set()
5+
6+
root.walkAtRules('apply', (rule) => {
7+
applyParents.add(rule.parent)
8+
})
9+
10+
if (applyParents.size === 0) {
11+
return
12+
}
13+
14+
for (let rule of applyParents) {
15+
let nodeGroups = []
16+
let lastGroup = []
17+
18+
for (let node of rule.nodes) {
19+
if (node.type === 'atrule' && node.name === 'apply') {
20+
if (lastGroup.length > 0) {
21+
nodeGroups.push(lastGroup)
22+
lastGroup = []
23+
}
24+
nodeGroups.push([node])
25+
} else {
26+
lastGroup.push(node)
27+
}
28+
}
29+
30+
if (lastGroup.length > 0) {
31+
nodeGroups.push(lastGroup)
32+
}
33+
34+
if (nodeGroups.length === 1) {
35+
continue
36+
}
37+
38+
for (let group of [...nodeGroups].reverse()) {
39+
let clone = rule.clone({ nodes: [] })
40+
clone.append(group)
41+
rule.after(clone)
42+
}
43+
44+
rule.remove()
45+
}
46+
}
47+
48+
export default function expandApplyAtRules() {
49+
return (root) => {
50+
partitionRules(root)
51+
}
52+
}

src/lib/setupContextUtils.js

+5-74
Original file line numberDiff line numberDiff line change
@@ -20,58 +20,6 @@ import log from '../util/log'
2020
import negateValue from '../util/negateValue'
2121
import isValidArbitraryValue from '../util/isValidArbitraryValue'
2222

23-
function partitionRules(root) {
24-
if (!root.walkAtRules) return [root]
25-
26-
let applyParents = new Set()
27-
let rules = []
28-
29-
root.walkAtRules('apply', (rule) => {
30-
applyParents.add(rule.parent)
31-
})
32-
33-
if (applyParents.size === 0) {
34-
rules.push(root)
35-
}
36-
37-
for (let rule of applyParents) {
38-
let nodeGroups = []
39-
let lastGroup = []
40-
41-
for (let node of rule.nodes) {
42-
if (node.type === 'atrule' && node.name === 'apply') {
43-
if (lastGroup.length > 0) {
44-
nodeGroups.push(lastGroup)
45-
lastGroup = []
46-
}
47-
nodeGroups.push([node])
48-
} else {
49-
lastGroup.push(node)
50-
}
51-
}
52-
53-
if (lastGroup.length > 0) {
54-
nodeGroups.push(lastGroup)
55-
}
56-
57-
if (nodeGroups.length === 1) {
58-
rules.push(rule)
59-
continue
60-
}
61-
62-
for (let group of [...nodeGroups].reverse()) {
63-
let clone = rule.clone({ nodes: [] })
64-
clone.append(group)
65-
rules.unshift(clone)
66-
rule.after(clone)
67-
}
68-
69-
rule.remove()
70-
}
71-
72-
return rules
73-
}
74-
7523
function parseVariantFormatString(input) {
7624
if (input.includes('{')) {
7725
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
@@ -284,9 +232,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
284232
context.candidateRuleMap.set(identifier, [])
285233
}
286234

287-
context.candidateRuleMap
288-
.get(identifier)
289-
.push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'user' }, rule]))
235+
context.candidateRuleMap.get(identifier).push([{ sort: offset, layer: 'user' }, rule])
290236
}
291237
},
292238
addBase(base) {
@@ -300,7 +246,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
300246

301247
context.candidateRuleMap
302248
.get(prefixedIdentifier)
303-
.push(...partitionRules(rule).map((rule) => [{ sort: offset, layer: 'base' }, rule]))
249+
.push([{ sort: offset, layer: 'base' }, rule])
304250
}
305251
},
306252
/**
@@ -321,12 +267,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
321267

322268
context.candidateRuleMap
323269
.get(prefixedIdentifier)
324-
.push(
325-
...partitionRules(rule).map((rule) => [
326-
{ sort: offsets.base++, layer: 'defaults' },
327-
rule,
328-
])
329-
)
270+
.push([{ sort: offsets.base++, layer: 'defaults' }, rule])
330271
}
331272
},
332273
addComponents(components, options) {
@@ -348,12 +289,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
348289

349290
context.candidateRuleMap
350291
.get(prefixedIdentifier)
351-
.push(
352-
...partitionRules(rule).map((rule) => [
353-
{ sort: offsets.components++, layer: 'components', options },
354-
rule,
355-
])
356-
)
292+
.push([{ sort: offsets.components++, layer: 'components', options }, rule])
357293
}
358294
},
359295
addUtilities(utilities, options) {
@@ -375,12 +311,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
375311

376312
context.candidateRuleMap
377313
.get(prefixedIdentifier)
378-
.push(
379-
...partitionRules(rule).map((rule) => [
380-
{ sort: offsets.utilities++, layer: 'utilities', options },
381-
rule,
382-
])
383-
)
314+
.push([{ sort: offsets.utilities++, layer: 'utilities', options }, rule])
384315
}
385316
},
386317
matchUtilities: function (utilities, options) {

src/processTailwindFeatures.js

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import substituteScreenAtRules from './lib/substituteScreenAtRules'
66
import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules'
77
import collapseAdjacentRules from './lib/collapseAdjacentRules'
88
import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations'
9+
import partitionApplyAtRules from './lib/partitionApplyAtRules'
910
import detectNesting from './lib/detectNesting'
1011
import { createContext } from './lib/setupContextUtils'
1112
import { issueFlagNotices } from './featureFlags'
@@ -15,6 +16,7 @@ export default function processTailwindFeatures(setupContext) {
1516
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
1617

1718
detectNesting()(root, result)
19+
partitionApplyAtRules()(root, result)
1820

1921
let context = setupContext({
2022
tailwindDirectives,

tests/apply.test.js

+63
Original file line numberDiff line numberDiff line change
@@ -1139,3 +1139,66 @@ it('apply does not emit defaults in isolated environments without optimizeUniver
11391139
`)
11401140
})
11411141
})
1142+
1143+
it('should work outside of layer', async () => {
1144+
let config = {
1145+
content: [{ raw: html`<div class="input-text"></div>` }],
1146+
corePlugins: { preflight: false },
1147+
}
1148+
1149+
let input = css`
1150+
.input-text {
1151+
@apply bg-white;
1152+
background-color: red;
1153+
}
1154+
`
1155+
1156+
let result
1157+
result = await run(input, config)
1158+
1159+
expect(result.css).toMatchFormattedCss(css`
1160+
.input-text {
1161+
--tw-bg-opacity: 1;
1162+
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1163+
background-color: red;
1164+
}
1165+
`)
1166+
1167+
result = await run(input, config)
1168+
1169+
expect(result.css).toMatchFormattedCss(css`
1170+
.input-text {
1171+
--tw-bg-opacity: 1;
1172+
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1173+
background-color: red;
1174+
}
1175+
`)
1176+
})
1177+
1178+
it('should work in layer', async () => {
1179+
let config = {
1180+
content: [{ raw: html`<div class="input-text"></div>` }],
1181+
corePlugins: { preflight: false },
1182+
}
1183+
1184+
let input = css`
1185+
@tailwind components;
1186+
@layer components {
1187+
.input-text {
1188+
@apply bg-white;
1189+
background-color: red;
1190+
}
1191+
}
1192+
`
1193+
1194+
await run(input, config)
1195+
const result = await run(input, config)
1196+
1197+
expect(result.css).toMatchFormattedCss(css`
1198+
.input-text {
1199+
--tw-bg-opacity: 1;
1200+
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
1201+
background-color: red;
1202+
}
1203+
`)
1204+
})

0 commit comments

Comments
 (0)