Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Commit f7129d5

Browse files
authored
Merge pull request #8 from tailwindlabs/refactor-to-postcss
Refactor from custom tuple format to PostCSS nodes
2 parents 836ae9a + 217b1ed commit f7129d5

12 files changed

+206
-572
lines changed

TODO.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,14 @@
8888
- [x] Support "unconditional" rules — styles that should be included in the CSS no matter what
8989
- [x] Unify components/utilities into single "rules" concept, remove tons of duplication
9090

91+
### Mar 5
92+
93+
- [x] Make rule tuple format support comments and any other node types (@font-face) properly (considering abandoning this entire data structure in favor of PostCSS)
94+
- [x] Unify base styles into the same "rules" abstraction
95+
9196
#### Next
9297

93-
- [ ] Make rule tuple format support comments and any other node types (@font-face) properly (considering abandoning this entire data structure in favor of PostCSS)
94-
- [ ] Unify base styles into the same "rules" abstraction
98+
- [ ] Support `modifySelectors` in variant API
9599
- [ ] Make prefixes work
96100
- [ ] Make important work
97101
- [ ] Make separator work

src/corePlugins/index.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
const postcss = require('postcss')
12
const nameClass = require('tailwindcss/lib/util/nameClass').default
23
const buildMediaQuery = require('tailwindcss/lib/util/buildMediaQuery').default
34
const transformThemeValue = require('tailwindcss/lib/util/transformThemeValue').default
45
const {
56
updateLastClasses,
67
updateAllClasses,
7-
transformRule,
88
transformAllSelectors,
99
transformAllClasses,
1010
transformLastClasses,
@@ -60,16 +60,22 @@ module.exports = {
6060

6161
addVariant(
6262
'motion-safe',
63-
transformLastClasses((className) => {
64-
return `motion-safe:${className}`
65-
}, '@media (prefers-reduced-motion: no-preference)')
63+
transformLastClasses(
64+
(className) => {
65+
return `motion-safe:${className}`
66+
},
67+
() => postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: no-preference)' })
68+
)
6669
)
6770

6871
addVariant(
6972
'motion-reduce',
70-
transformLastClasses((className) => {
71-
return `motion-reduce:${className}`
72-
}, '@media (prefers-reduced-motion: reduce)')
73+
transformLastClasses(
74+
(className) => {
75+
return `motion-reduce:${className}`
76+
},
77+
() => postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: reduce)' })
78+
)
7379
)
7480

7581
addVariant(
@@ -104,9 +110,12 @@ module.exports = {
104110
} else if (config.darkMode === 'media') {
105111
addVariant(
106112
'dark',
107-
transformLastClasses((className) => {
108-
return `dark:${className}`
109-
}, '@media (prefers-color-scheme: dark)')
113+
transformLastClasses(
114+
(className) => {
115+
return `dark:${className}`
116+
},
117+
() => postcss.atRule({ name: 'media', params: '(prefers-color-scheme: dark)' })
118+
)
110119
)
111120
}
112121

@@ -116,9 +125,12 @@ module.exports = {
116125

117126
addVariant(
118127
screen,
119-
transformLastClasses((className) => {
120-
return `${screen}:${className}`
121-
}, `@media ${query}`)
128+
transformLastClasses(
129+
(className) => {
130+
return `${screen}:${className}`
131+
},
132+
() => postcss.atRule({ name: 'media', params: query })
133+
)
122134
)
123135
}
124136
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div
2+
class="opacity-50 custom-util hover:custom-util group-hover:custom-util foo:custom-util foo:hover:custom-util sm:custom-util dark:custom-util motion-safe:custom-util md:dark:motion-safe:foo:active:custom-util"
3+
></div>

src/index.test.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
color: purple;
1010
}
1111
}
12+
.apply-1 {
13+
margin-top: 1.5rem;
14+
}
15+
.apply-2 {
16+
margin-top: 1.5rem;
17+
}
1218
.apply-test {
1319
margin-top: 1.5rem;
1420
--tw-bg-opacity: 1;
@@ -223,6 +229,9 @@ div {
223229
* {
224230
padding: 5px;
225231
}
232+
.mt-6 {
233+
margin-top: 1.5rem;
234+
}
226235
.grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] {
227236
grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
228237
}
@@ -331,6 +340,9 @@ div {
331340
.hover\:font-bold:hover {
332341
font-weight: 700;
333342
}
343+
.hover\:custom-util:hover {
344+
background: #abcdef;
345+
}
334346
.focus\:font-normal:focus {
335347
font-weight: 400;
336348
}
@@ -354,6 +366,9 @@ div {
354366
.group:hover .group-hover\:opacity-100 {
355367
opacity: 1;
356368
}
369+
.group:hover .group-hover\:custom-util {
370+
background: #abcdef;
371+
}
357372
.group:active .group-active\:opacity-10 {
358373
opacity: 0.1;
359374
}
@@ -364,6 +379,9 @@ div {
364379
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
365380
transition-duration: 150ms;
366381
}
382+
.motion-safe\:custom-util {
383+
background: #abcdef;
384+
}
367385
}
368386
@media (prefers-reduced-motion: reduce) {
369387
.motion-reduce\:transition {
@@ -373,6 +391,15 @@ div {
373391
transition-duration: 150ms;
374392
}
375393
}
394+
.dark .dark\:custom-util {
395+
background: #abcdef;
396+
}
397+
.foo\:custom-util {
398+
background: #abcdef !important;
399+
}
400+
.foo\:hover\:custom-util:hover {
401+
background: #abcdef !important;
402+
}
376403
@media (min-width: 640px) {
377404
.sm\:container {
378405
width: 100%;
@@ -424,6 +451,9 @@ div {
424451
.sm\:text-center {
425452
text-align: center;
426453
}
454+
.sm\:custom-util {
455+
background: #abcdef;
456+
}
427457
@media (prefers-reduced-motion: no-preference) {
428458
.group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus {
429459
opacity: 0.1;
@@ -481,6 +511,11 @@ div {
481511
transition-duration: 150ms;
482512
}
483513
}
514+
@media (prefers-reduced-motion: no-preference) {
515+
.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active {
516+
background: #abcdef !important;
517+
}
518+
}
484519
}
485520
@media (min-width: 640px) {
486521
@media (min-width: 768px) {

src/index.test.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@
1313
class="container hover:container sm:container md:container text-center sm:text-center md:text-center"
1414
></div>
1515
<div class="grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
16+
<div class="mt-6"></div>
17+
<div class="custom-util"></div>
18+
<div class="hover:custom-util"></div>
19+
<div class="group-hover:custom-util"></div>
20+
<div class="foo:custom-util"></div>
21+
<div class="foo:hover:custom-util"></div>
22+
<div class="sm:custom-util"></div>
23+
<div class="dark:custom-util"></div>
24+
<div class="motion-safe:custom-util"></div>
25+
<div class="md:dark:motion-safe:foo:active:custom-util"></div>
1626
<div class="aspect-w-1 aspect-h-2"></div>
1727
<div class="aspect-w-3 aspect-h-4"></div>
1828
<div class="filter-none filter-grayscale"></div>

src/index.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,20 @@ test('it works', () => {
2525
},
2626
plugins: [
2727
require('@tailwindcss/aspect-ratio'),
28+
function ({ addVariant }) {
29+
addVariant(
30+
'foo',
31+
({ container }) => {
32+
container.walkRules((rule) => {
33+
rule.selector = `.foo\\:${rule.selector.slice(1)}`
34+
rule.walkDecls((decl) => {
35+
decl.important = true
36+
})
37+
})
38+
},
39+
{ before: 'sm' }
40+
)
41+
},
2842
function ({ addUtilities, addBase, theme }) {
2943
addBase({
3044
h1: {
@@ -81,6 +95,12 @@ test('it works', () => {
8195
color: purple;
8296
}
8397
}
98+
.apply-1 {
99+
@apply mt-6;
100+
}
101+
.apply-2 {
102+
@apply mt-6;
103+
}
84104
.apply-test {
85105
@apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200;
86106
}

src/lib/expandApplyAtRules.js

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
const postcss = require('postcss')
12
const generateRules = require('./generateRules')
2-
const { bigSign, toPostCssNode, isPlainObject } = require('./utils')
3+
const { bigSign } = require('./utils')
34
const escape = require('tailwindcss/lib/util/escapeClassName').default
45

56
function expandApplyAtRules(context) {
@@ -17,9 +18,15 @@ function expandApplyAtRules(context) {
1718

1819
// Start the @apply process if we have rules with @apply in them
1920
if (applies.length > 0) {
21+
let classCacheCount = context.classCache.size
22+
2023
// Fill up some caches!
2124
generateRules(context.tailwindConfig, applyCandidates, context)
2225

26+
if (context.classCache.size > classCacheCount) {
27+
context.stylesheetCache = null
28+
}
29+
2330
/**
2431
* When we have an apply like this:
2532
*
@@ -48,15 +55,6 @@ function expandApplyAtRules(context) {
4855
.join(', ')
4956
}
5057

51-
function updateSelectors(rule, apply, candidate) {
52-
return rule.map(([selector, rule]) => {
53-
if (!isPlainObject(rule)) {
54-
return [selector, updateSelectors(rule, apply, candidate)]
55-
}
56-
return [replaceSelector(apply.parent.selector, selector, candidate), rule]
57-
})
58-
}
59-
6058
for (let apply of applies) {
6159
let siblings = []
6260
let applyCandidates = apply.params.split(/[\s\t\n]+/g)
@@ -67,16 +65,15 @@ function expandApplyAtRules(context) {
6765
}
6866

6967
let rules = context.classCache.get(applyCandidate)
70-
for (let [meta, [selector, rule]] of rules) {
71-
siblings.push([
72-
meta,
73-
toPostCssNode(
74-
!isPlainObject(rule)
75-
? [selector, updateSelectors(rule, apply, applyCandidate)]
76-
: [replaceSelector(apply.parent.selector, selector, applyCandidate), rule],
77-
context.postCssNodeCache
78-
),
79-
])
68+
69+
for (let [meta, node] of rules) {
70+
let root = postcss.root({ nodes: [node] })
71+
72+
root.walkRules((rule) => {
73+
rule.selector = replaceSelector(apply.parent.selector, rule.selector, applyCandidate)
74+
})
75+
76+
siblings.push([meta, root.nodes[0]])
8077
}
8178
}
8279

src/lib/expandTailwindAtRules.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const fs = require('fs')
22
const fastGlob = require('fast-glob')
33
const sharedState = require('./sharedState')
44
const generateRules = require('./generateRules')
5-
const { bigSign, toPostCssNode } = require('./utils')
5+
const { bigSign } = require('./utils')
66

77
let env = sharedState.env
88
let contentMatchCache = sharedState.contentMatchCache
@@ -46,6 +46,7 @@ function buildStylesheet(rules, context) {
4646
let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))
4747

4848
let returnValue = {
49+
base: new Set(),
4950
components: new Set(),
5051
utilities: new Set(),
5152
screens: new Set(),
@@ -57,6 +58,11 @@ function buildStylesheet(rules, context) {
5758
continue
5859
}
5960

61+
if (sort & context.layerOrder.base) {
62+
returnValue.base.add(rule)
63+
continue
64+
}
65+
6066
if (sort & context.layerOrder.components) {
6167
returnValue.components.add(rule)
6268
continue
@@ -152,17 +158,18 @@ function expandTailwindAtRules(context, registerDependency) {
152158
env.DEBUG && console.timeEnd('Generate rules')
153159

154160
// We only ever add to the classCache, so if it didn't grow, there is nothing new.
161+
env.DEBUG && console.time('Build stylesheet')
155162
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
156-
env.DEBUG && console.time('Build stylesheet')
157163
for (let rule of rules) {
158164
context.ruleCache.add(rule)
159165
}
160166

161167
context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
162-
env.DEBUG && console.timeEnd('Build stylesheet')
163168
}
169+
env.DEBUG && console.timeEnd('Build stylesheet')
164170

165171
let {
172+
base: baseNodes,
166173
components: componentNodes,
167174
utilities: utilityNodes,
168175
screens: screenNodes,
@@ -173,7 +180,7 @@ function expandTailwindAtRules(context, registerDependency) {
173180
// Replace any Tailwind directives with generated CSS
174181

175182
if (layerNodes.base) {
176-
layerNodes.base.before([...context.baseRules])
183+
layerNodes.base.before([...baseNodes])
177184
layerNodes.base.remove()
178185
}
179186

0 commit comments

Comments
 (0)