Skip to content

Commit df31370

Browse files
committed
Merge branch 'master' into resolve-purge-paths
2 parents f3ad750 + e764df5 commit df31370

File tree

85 files changed

+73502
-73705
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+73502
-73705
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Add `background-origin` utilities ([#4117](https://github.com/tailwindlabs/tailwindcss/pull/4117))
13+
- Improve `@apply` performance in projects that process many CSS sources ([#3178](https://github.com/tailwindlabs/tailwindcss/pull/3718))
14+
- JIT: Don't use CSS variables for color utilities if color opacity utilities are disabled ([#3984](https://github.com/tailwindlabs/tailwindcss/pull/3984))
15+
- JIT: Redesign `matchUtilities` API to make it more suitable for third-party use ([#4232](https://github.com/tailwindlabs/tailwindcss/pull/4232))
16+
- JIT: Support applying important utility variants ([#4260](https://github.com/tailwindlabs/tailwindcss/pull/4260))
17+
18+
### Fixed
19+
20+
- JIT: Improve support for Svelte class bindings ([#4187](https://github.com/tailwindlabs/tailwindcss/pull/4187))
21+
- JIT: Improve support for `calc` and `var` in arbitrary values ([#4147](https://github.com/tailwindlabs/tailwindcss/pull/4147))
22+
- Convert `hsl` colors to `hsla` when transforming for opacity support instead of `rgba` ([#3850](https://github.com/tailwindlabs/tailwindcss/pull/3850))
23+
- Fix `backdropBlur` variants not being generated ([#4188](https://github.com/tailwindlabs/tailwindcss/pull/4188))
24+
- Improve animation value parsing ([#4250](https://github.com/tailwindlabs/tailwindcss/pull/4250))
25+
- Ignore unknown object types when hashing config ([82f4eaa](https://github.com/tailwindlabs/tailwindcss/commit/82f4eaa6832ef8a4e3fd90869e7068efdf6e34f2))
1326

1427
## [2.1.2] - 2021-04-23
1528

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"eslint-config-prettier": "^7.2.0",
5252
"eslint-plugin-prettier": "^3.4.0",
5353
"jest": "^26.6.3",
54-
"postcss": "^8.2.8",
54+
"postcss": "^8.2.13",
5555
"postcss-cli": "^8.3.1",
5656
"prettier": "^2.2.1",
5757
"rimraf": "^3.0.0"

src/jit/lib/expandApplyAtRules.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ function buildApplyCache(applyCandidates, context) {
3030
return context.applyClassCache
3131
}
3232

33-
// TODO: Apply `!important` stuff correctly instead of just skipping it
3433
function extractApplyCandidates(params) {
3534
let candidates = params.split(/[\s\t\n]+/g)
3635

@@ -143,7 +142,6 @@ function processApply(root, context) {
143142
.join(', ')
144143
}
145144

146-
/** @type {Map<import('postcss').Node, [string, boolean, import('postcss').Node[]][]>} */
147145
let perParentApplies = new Map()
148146

149147
// Collect all apply candidates and their rules
@@ -197,7 +195,7 @@ function processApply(root, context) {
197195
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate)
198196

199197
rule.walkDecls((d) => {
200-
d.important = important
198+
d.important = meta.important || important
201199
})
202200
})
203201
}

src/jit/lib/expandTailwindAtRules.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ function getDefaultExtractor(fileExtension) {
2525
}
2626
}
2727

28-
function getExtractor(fileName, tailwindConfig) {
28+
function getExtractor(tailwindConfig, fileExtension) {
2929
const purgeOptions = tailwindConfig && tailwindConfig.purge && tailwindConfig.purge.options
30-
const fileExtension = path.extname(fileName).slice(1)
30+
31+
if (!fileExtension) {
32+
return (purgeOptions && purgeOptions.defaultExtractor) || getDefaultExtractor()
33+
}
3134

3235
if (!purgeOptions) {
3336
return getDefaultExtractor(fileExtension)
@@ -208,11 +211,16 @@ export default function expandTailwindAtRules(context, registerDependency) {
208211
env.DEBUG && console.time('Reading changed files')
209212
for (let file of context.changedFiles) {
210213
let content = fs.readFileSync(file, 'utf8')
211-
let extractor = getExtractor(file, context.tailwindConfig)
214+
let extractor = getExtractor(context.tailwindConfig, path.extname(file).slice(1))
212215
getClassCandidates(content, extractor, contentMatchCache, candidates, seen)
213216
}
214217
env.DEBUG && console.timeEnd('Reading changed files')
215218

219+
for (let { content, extension } of context.rawContent) {
220+
let extractor = getExtractor(context.tailwindConfig, extension)
221+
getClassCandidates(content, extractor, contentMatchCache, candidates, seen)
222+
}
223+
216224
// ---
217225

218226
// Generate the actual CSS

src/jit/lib/generateRules.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function applyImportant(matches) {
7979
})
8080
r.walkDecls((d) => (d.important = true))
8181
})
82-
result.push([meta, container.nodes[0]])
82+
result.push([{ ...meta, important: true }, container.nodes[0]])
8383
}
8484

8585
return result
@@ -192,9 +192,13 @@ function* resolveMatchedPlugins(classCandidate, context) {
192192
}
193193
}
194194

195+
function splitWithSeparator(input, separator) {
196+
return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
197+
}
198+
195199
function* resolveMatches(candidate, context) {
196200
let separator = context.tailwindConfig.separator
197-
let [classCandidate, ...variants] = candidate.split(separator).reverse()
201+
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
198202
let important = false
199203

200204
if (classCandidate.startsWith('!')) {
@@ -215,17 +219,12 @@ function* resolveMatches(candidate, context) {
215219
// }
216220

217221
for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)) {
218-
let pluginHelpers = {
219-
candidate: classCandidate,
220-
theme: context.tailwindConfig.theme,
221-
}
222-
223222
let matches = []
224223
let [plugins, modifier] = matchedPlugins
225224

226225
for (let [sort, plugin] of plugins) {
227226
if (typeof plugin === 'function') {
228-
for (let ruleSet of [].concat(plugin(modifier, pluginHelpers))) {
227+
for (let ruleSet of [].concat(plugin(modifier))) {
229228
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
230229
for (let rule of rules) {
231230
matches.push([{ ...sort, options: { ...sort.options, ...options } }, rule])

src/jit/lib/setupContext.js

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import path from 'path'
55
import crypto from 'crypto'
66
import chokidar from 'chokidar'
77
import postcss from 'postcss'
8-
import hash from 'object-hash'
98
import dlv from 'dlv'
109
import selectorParser from 'postcss-selector-parser'
1110
import LRU from 'quick-lru'
1211
import normalizePath from 'normalize-path'
1312

13+
import hash from '../../util/hashConfig'
1414
import transformThemeValue from '../../util/transformThemeValue'
1515
import parseObjectStyles from '../../util/parseObjectStyles'
1616
import getModuleDependencies from '../../lib/getModuleDependencies'
@@ -22,6 +22,9 @@ import corePlugins from '../corePlugins'
2222
import isPlainObject from '../../util/isPlainObject'
2323
import escapeClassName from '../../util/escapeClassName'
2424

25+
import nameClass from '../../util/nameClass'
26+
import { coerceValue } from '../../util/pluginUtils'
27+
2528
import * as sharedState from './sharedState'
2629

2730
let contextMap = sharedState.contextMap
@@ -513,36 +516,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
513516
.push([{ sort: offset, layer: 'utilities', options }, rule])
514517
}
515518
},
516-
matchBase: function (base) {
517-
let offset = offsets.base++
518-
519-
for (let identifier in base) {
520-
let prefixedIdentifier = prefixIdentifier(identifier, options)
521-
let rule = base[identifier]
522-
523-
let withOffsets = [{ sort: offset, layer: 'base' }, rule]
524-
525-
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
526-
context.candidateRuleMap.set(prefixedIdentifier, [])
527-
}
528-
529-
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
530-
}
531-
},
532519
matchUtilities: function (utilities, options) {
533-
// TODO: Redesign this API to work like this so it's more end-user friendly
534-
// matchUtilities({
535-
// animate: (value, { includeRules }) => {
536-
// let { name: animationName } = parseAnimationValue(value)
537-
538-
// if (keyframes[animationName] !== undefined) {
539-
// includeRules(keyframes[animationName])
540-
// }
541-
542-
// return { animation: value }
543-
// },
544-
// }, { values: [...], variants: [lol], ...otherStuff })
545-
546520
let defaultOptions = {
547521
variants: [],
548522
respectPrefix: true,
@@ -558,7 +532,32 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
558532
let prefixedIdentifier = prefixIdentifier(identifier, options)
559533
let rule = utilities[identifier]
560534

561-
let withOffsets = [{ sort: offset, layer: 'utilities', options }, rule]
535+
function wrapped(modifier) {
536+
let { type = 'any' } = options
537+
let [value, coercedType] = coerceValue(type, modifier, options.values)
538+
539+
if (type !== coercedType || value === undefined) {
540+
return []
541+
}
542+
543+
let includedRules = []
544+
let ruleSets = []
545+
.concat(
546+
rule(value, {
547+
includeRules(rules) {
548+
includedRules.push(...rules)
549+
},
550+
})
551+
)
552+
.filter(Boolean)
553+
.map((declaration) => ({
554+
[nameClass(identifier, modifier)]: declaration,
555+
}))
556+
557+
return [...includedRules, ...ruleSets]
558+
}
559+
560+
let withOffsets = [{ sort: offset, layer: 'utilities', options }, wrapped]
562561

563562
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
564563
context.candidateRuleMap.set(prefixedIdentifier, [])
@@ -567,16 +566,6 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
567566
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
568567
}
569568
},
570-
// ---
571-
jit: {
572-
e: escapeClassName,
573-
config: tailwindConfig,
574-
theme: tailwindConfig.theme,
575-
addVariant(variantName, applyVariant, options = {}) {
576-
insertInto(variantList, variantName, options)
577-
variantMap.set(variantName, applyVariant)
578-
},
579-
},
580569
}
581570
}
582571

@@ -776,19 +765,11 @@ export default function setupContext(configOrPath) {
776765
}
777766
}
778767

779-
let candidateFiles = (Array.isArray(tailwindConfig.purge)
768+
process.env.DEBUG && console.log('Setting up new context...')
769+
770+
let purgeContent = Array.isArray(tailwindConfig.purge)
780771
? tailwindConfig.purge
781772
: tailwindConfig.purge.content
782-
)
783-
.map((purgePath) =>
784-
path.resolve(
785-
userConfigPath === null ? process.cwd() : path.dirname(userConfigPath),
786-
purgePath
787-
)
788-
)
789-
.map((purgePath) => normalizePath(purgePath))
790-
791-
process.env.DEBUG && console.log('Setting up new context...')
792773

793774
let context = {
794775
changedFiles: new Set(),
@@ -804,7 +785,19 @@ export default function setupContext(configOrPath) {
804785
configPath: userConfigPath,
805786
tailwindConfig: tailwindConfig,
806787
configDependencies: new Set(),
807-
candidateFiles,
788+
candidateFiles: purgeContent
789+
.filter((item) => typeof item === 'string')
790+
.map((purgePath) =>
791+
normalizePath(
792+
path.resolve(
793+
userConfigPath === null ? process.cwd() : path.dirname(userConfigPath),
794+
purgePath
795+
)
796+
)
797+
),
798+
rawContent: purgeContent
799+
.filter((item) => typeof item.raw === 'string')
800+
.map(({ raw, extension }) => ({ content: raw, extension })),
808801
variantMap: new Map(),
809802
stylesheetCache: null,
810803
fileModifiedMap: new Map(),

src/plugins/animation.js

Lines changed: 30 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,41 @@
1-
import _ from 'lodash'
21
import parseAnimationValue from '../util/parseAnimationValue'
3-
import nameClass from '../util/nameClass'
42

53
export default function () {
6-
return function ({ config, matchUtilities, addUtilities, theme, variants, prefix }) {
7-
if (config('mode') === 'jit') {
8-
let keyframes = Object.fromEntries(
9-
Object.entries(theme('keyframes')).map(([key, value]) => {
10-
return [
11-
key,
12-
[
13-
{
14-
[`@keyframes ${key}`]: value,
15-
},
16-
{ respectVariants: false },
17-
],
18-
]
19-
})
20-
)
4+
return function ({ matchUtilities, theme, variants, prefix }) {
5+
let prefixName = (name) => prefix(`.${name}`).slice(1)
6+
let keyframes = Object.fromEntries(
7+
Object.entries(theme('keyframes')).map(([key, value]) => {
8+
return [
9+
key,
10+
[
11+
{
12+
[`@keyframes ${prefixName(key)}`]: value,
13+
},
14+
{ respectVariants: false },
15+
],
16+
]
17+
})
18+
)
2119

22-
matchUtilities({
23-
animate: (modifier, { theme }) => {
24-
let value = theme.animation[modifier]
20+
matchUtilities(
21+
{
22+
animate: (value, { includeRules }) => {
23+
let { name: animationName } = parseAnimationValue(value)
2524

26-
if (value === undefined) {
27-
return []
25+
if (keyframes[animationName] !== undefined) {
26+
includeRules(keyframes[animationName], { respectImportant: false })
2827
}
2928

30-
let { name: animationName } = parseAnimationValue(value)
29+
if (animationName === undefined || keyframes[animationName] === undefined) {
30+
return { animation: value }
31+
}
3132

32-
return [
33-
keyframes[animationName],
34-
{ [nameClass('animate', modifier)]: { animation: value } },
35-
].filter(Boolean)
33+
return {
34+
animation: value.replace(animationName, prefixName(animationName)),
35+
}
3636
},
37-
})
38-
} else {
39-
const prefixName = (name) => prefix(`.${name}`).slice(1)
40-
const keyframesConfig = theme('keyframes')
41-
const keyframesStyles = _.mapKeys(
42-
keyframesConfig,
43-
(_keyframes, name) => `@keyframes ${prefixName(name)}`
44-
)
45-
46-
addUtilities(keyframesStyles, { respectImportant: false })
47-
48-
const animationConfig = theme('animation')
49-
const utilities = _.mapValues(
50-
_.mapKeys(animationConfig, (_animation, suffix) => nameClass('animate', suffix)),
51-
(animation) => {
52-
const { name } = parseAnimationValue(animation)
53-
if (name === undefined || keyframesConfig[name] === undefined) return { animation }
54-
return { animation: animation.replace(name, prefixName(name)) }
55-
}
56-
)
57-
addUtilities(utilities, variants('animation'))
58-
}
37+
},
38+
{ values: theme('animation'), variants: variants('animation') }
39+
)
5940
}
6041
}

0 commit comments

Comments
 (0)