Remove AOT (#5340)
* make `jit` mode the default when no mode is specified
* unify JIT and AOT codepaths
* ensure `Object.entries` on undefined doesn't break
It could be that sometimes you don't have values in your config (e.g.: `presets: []`), this in turn will break some plugins where we assume we have a value.
* drop AOT specific tests
These tests are all covered by JIT mode already and were AOT specific.
* simplify tests, and add a few
Some of the tests were written for AOT specifically, some were missing. We also updated the way we write those tests, essentially making Tailwind a blackbox, by testing against the final output.
Now that JIT mode is the default, this is super fast because we only generate what is used, instead of partially testing in a 3MB file or building it all, then purging.
* add some todo's to make sure we warn in a few cases
* make `darkMode: 'media'`, the default
This also includes moving dark mode tests to its own dedicated file.
* remove PostCSS 7 compat mode
* update CLI to be JIT-first
* fix integration tests
This is not a _real_ fix, but it does solve the broken test for now.
* warn when using @responsive or @variants
* remove the JIT preview warning
* remove AOT-only code paths
* remove all `mode: 'jit'` blocks
Also remove `variants: {}` since they are not useful in `JIT` mode
anymore.
* drop unused dependencies
* rename `purge` to `content`
* remove static CDN builds
* mark `--purge` as deprecated in the CLI
This will still work, but a warning will be printed and it won't show up
in the `--help` output.
* cleanup nesting plugin
We don't have to duplicate it anymore since there is no PostCSS 7
version anymore.
* make sure integration tests run in band
* cleanup folder structure
* make sure nesting folder is available
* simplify resolving of purge/content information
This commit is contained in:
parent
911e755056
commit
691ed02f63
141 changed files with 1991 additions and 10609 deletions
|
|
@ -1,57 +1,335 @@
|
|||
import * as plugins from './plugins/index.js'
|
||||
import configurePlugins from './util/configurePlugins'
|
||||
import postcss from 'postcss'
|
||||
import * as corePlugins from './plugins'
|
||||
import buildMediaQuery from './util/buildMediaQuery'
|
||||
import prefixSelector from './util/prefixSelector'
|
||||
import {
|
||||
applyPseudoToMarker,
|
||||
updateLastClasses,
|
||||
updateAllClasses,
|
||||
transformAllSelectors,
|
||||
transformAllClasses,
|
||||
transformLastClasses,
|
||||
} from './util/pluginUtils'
|
||||
import log from './util/log'
|
||||
|
||||
function move(items, item, befores) {
|
||||
let lowestBefore = -1
|
||||
export default {
|
||||
pseudoElementVariants: function ({ config, addVariant }) {
|
||||
addVariant(
|
||||
'first-letter',
|
||||
transformAllSelectors((selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`first-letter${config('separator')}${className}`, '::first-letter')
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
for (let before of befores) {
|
||||
let index = items.indexOf(before)
|
||||
if (index >= 0 && (index < lowestBefore || lowestBefore === -1)) {
|
||||
lowestBefore = index
|
||||
addVariant(
|
||||
'first-line',
|
||||
transformAllSelectors((selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`first-line${config('separator')}${className}`, '::first-line')
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
addVariant('marker', [
|
||||
transformAllSelectors((selector) => {
|
||||
let variantSelector = updateAllClasses(selector, (className) => {
|
||||
return `marker${config('separator')}${className}`
|
||||
})
|
||||
|
||||
return `${variantSelector} *::marker`
|
||||
}),
|
||||
transformAllSelectors((selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`marker${config('separator')}${className}`, '::marker')
|
||||
})
|
||||
}),
|
||||
])
|
||||
|
||||
addVariant('selection', [
|
||||
transformAllSelectors((selector) => {
|
||||
let variantSelector = updateAllClasses(selector, (className) => {
|
||||
return `selection${config('separator')}${className}`
|
||||
})
|
||||
|
||||
return `${variantSelector} *::selection`
|
||||
}),
|
||||
transformAllSelectors((selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`selection${config('separator')}${className}`, '::selection')
|
||||
})
|
||||
}),
|
||||
])
|
||||
|
||||
addVariant(
|
||||
'before',
|
||||
transformAllSelectors(
|
||||
(selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`before${config('separator')}${className}`, '::before')
|
||||
})
|
||||
},
|
||||
{
|
||||
withRule: (rule) => {
|
||||
let foundContent = false
|
||||
rule.walkDecls('content', () => {
|
||||
foundContent = true
|
||||
})
|
||||
if (!foundContent) {
|
||||
rule.prepend(postcss.decl({ prop: 'content', value: '""' }))
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
addVariant(
|
||||
'after',
|
||||
transformAllSelectors(
|
||||
(selector) => {
|
||||
return updateAllClasses(selector, (className, { withPseudo }) => {
|
||||
return withPseudo(`after${config('separator')}${className}`, '::after')
|
||||
})
|
||||
},
|
||||
{
|
||||
withRule: (rule) => {
|
||||
let foundContent = false
|
||||
rule.walkDecls('content', () => {
|
||||
foundContent = true
|
||||
})
|
||||
if (!foundContent) {
|
||||
rule.prepend(postcss.decl({ prop: 'content', value: '""' }))
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
},
|
||||
pseudoClassVariants: function ({ config, addVariant }) {
|
||||
let pseudoVariants = [
|
||||
// Positional
|
||||
['first', 'first-child'],
|
||||
['last', 'last-child'],
|
||||
['only', 'only-child'],
|
||||
['odd', 'nth-child(odd)'],
|
||||
['even', 'nth-child(even)'],
|
||||
'first-of-type',
|
||||
'last-of-type',
|
||||
'only-of-type',
|
||||
|
||||
// State
|
||||
'visited',
|
||||
'target',
|
||||
|
||||
// Forms
|
||||
'default',
|
||||
'checked',
|
||||
'indeterminate',
|
||||
'placeholder-shown',
|
||||
'autofill',
|
||||
'required',
|
||||
'valid',
|
||||
'invalid',
|
||||
'in-range',
|
||||
'out-of-range',
|
||||
'read-only',
|
||||
|
||||
// Content
|
||||
'empty',
|
||||
|
||||
// Interactive
|
||||
'focus-within',
|
||||
'hover',
|
||||
'focus',
|
||||
'focus-visible',
|
||||
'active',
|
||||
'disabled',
|
||||
]
|
||||
|
||||
for (let variant of pseudoVariants) {
|
||||
let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant]
|
||||
|
||||
addVariant(
|
||||
variantName,
|
||||
transformAllClasses((className, { withPseudo }) => {
|
||||
return withPseudo(`${variantName}${config('separator')}${className}`, `:${state}`)
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (items.indexOf(item) === -1 || lowestBefore === -1) {
|
||||
return items
|
||||
}
|
||||
let groupMarker = prefixSelector(config('prefix'), '.group')
|
||||
for (let variant of pseudoVariants) {
|
||||
let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant]
|
||||
let groupVariantName = `group-${variantName}`
|
||||
|
||||
items = [...items]
|
||||
let fromIndex = items.indexOf(item)
|
||||
let toIndex = lowestBefore
|
||||
items.splice(fromIndex, 1)
|
||||
items.splice(toIndex, 0, item)
|
||||
return items
|
||||
}
|
||||
|
||||
export default function ({ corePlugins: corePluginConfig }) {
|
||||
let pluginOrder = Object.keys(plugins)
|
||||
|
||||
pluginOrder = configurePlugins(corePluginConfig, pluginOrder)
|
||||
pluginOrder = move(pluginOrder, 'transform', ['translate', 'rotate', 'skew', 'scale'])
|
||||
pluginOrder = move(pluginOrder, 'filter', [
|
||||
'blur',
|
||||
'brightness',
|
||||
'contrast',
|
||||
'dropShadow',
|
||||
'grayscale',
|
||||
'hueRotate',
|
||||
'invert',
|
||||
'saturate',
|
||||
'sepia',
|
||||
])
|
||||
pluginOrder = move(pluginOrder, 'backdropFilter', [
|
||||
'backdropBlur',
|
||||
'backdropBrightness',
|
||||
'backdropContrast',
|
||||
'backdropGrayscale',
|
||||
'backdropHueRotate',
|
||||
'backdropInvert',
|
||||
'backdropOpacity',
|
||||
'backdropSaturate',
|
||||
'backdropSepia',
|
||||
])
|
||||
|
||||
return pluginOrder.map((pluginName) => {
|
||||
return plugins[pluginName]()
|
||||
})
|
||||
addVariant(
|
||||
groupVariantName,
|
||||
transformAllSelectors((selector) => {
|
||||
let variantSelector = updateAllClasses(selector, (className) => {
|
||||
if (`.${className}` === groupMarker) return className
|
||||
return `${groupVariantName}${config('separator')}${className}`
|
||||
})
|
||||
|
||||
if (variantSelector === selector) {
|
||||
return null
|
||||
}
|
||||
|
||||
return applyPseudoToMarker(
|
||||
variantSelector,
|
||||
groupMarker,
|
||||
state,
|
||||
(marker, selector) => `${marker} ${selector}`
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
let peerMarker = prefixSelector(config('prefix'), '.peer')
|
||||
for (let variant of pseudoVariants) {
|
||||
let [variantName, state] = Array.isArray(variant) ? variant : [variant, variant]
|
||||
let peerVariantName = `peer-${variantName}`
|
||||
|
||||
addVariant(
|
||||
peerVariantName,
|
||||
transformAllSelectors((selector) => {
|
||||
let variantSelector = updateAllClasses(selector, (className) => {
|
||||
if (`.${className}` === peerMarker) return className
|
||||
return `${peerVariantName}${config('separator')}${className}`
|
||||
})
|
||||
|
||||
if (variantSelector === selector) {
|
||||
return null
|
||||
}
|
||||
|
||||
return applyPseudoToMarker(variantSelector, peerMarker, state, (marker, selector) =>
|
||||
selector.trim().startsWith('~') ? `${marker}${selector}` : `${marker} ~ ${selector}`
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
directionVariants: function ({ config, addVariant }) {
|
||||
addVariant(
|
||||
'ltr',
|
||||
transformAllSelectors(
|
||||
(selector) =>
|
||||
`[dir="ltr"] ${updateAllClasses(
|
||||
selector,
|
||||
(className) => `ltr${config('separator')}${className}`
|
||||
)}`
|
||||
)
|
||||
)
|
||||
|
||||
addVariant(
|
||||
'rtl',
|
||||
transformAllSelectors(
|
||||
(selector) =>
|
||||
`[dir="rtl"] ${updateAllClasses(
|
||||
selector,
|
||||
(className) => `rtl${config('separator')}${className}`
|
||||
)}`
|
||||
)
|
||||
)
|
||||
},
|
||||
reducedMotionVariants: function ({ config, addVariant }) {
|
||||
addVariant(
|
||||
'motion-safe',
|
||||
transformLastClasses(
|
||||
(className) => {
|
||||
return `motion-safe${config('separator')}${className}`
|
||||
},
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: no-preference)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
addVariant(
|
||||
'motion-reduce',
|
||||
transformLastClasses(
|
||||
(className) => {
|
||||
return `motion-reduce${config('separator')}${className}`
|
||||
},
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-reduced-motion: reduce)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
},
|
||||
darkVariants: function ({ config, addVariant }) {
|
||||
let mode = config('darkMode', 'media')
|
||||
if (mode === false) {
|
||||
mode = 'media'
|
||||
log.warn([
|
||||
'`darkMode` is set to `false` in your config.',
|
||||
'This will behave just like the `media` value.',
|
||||
])
|
||||
}
|
||||
|
||||
if (mode === 'class') {
|
||||
addVariant(
|
||||
'dark',
|
||||
transformAllSelectors((selector) => {
|
||||
let variantSelector = updateLastClasses(selector, (className) => {
|
||||
return `dark${config('separator')}${className}`
|
||||
})
|
||||
|
||||
if (variantSelector === selector) {
|
||||
return null
|
||||
}
|
||||
|
||||
let darkSelector = prefixSelector(config('prefix'), `.dark`)
|
||||
|
||||
return `${darkSelector} ${variantSelector}`
|
||||
})
|
||||
)
|
||||
} else if (mode === 'media') {
|
||||
addVariant(
|
||||
'dark',
|
||||
transformLastClasses(
|
||||
(className) => {
|
||||
return `dark${config('separator')}${className}`
|
||||
},
|
||||
{
|
||||
wrap: () =>
|
||||
postcss.atRule({
|
||||
name: 'media',
|
||||
params: '(prefers-color-scheme: dark)',
|
||||
}),
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
screenVariants: function ({ config, theme, addVariant }) {
|
||||
for (let screen in theme('screens')) {
|
||||
let size = theme('screens')[screen]
|
||||
let query = buildMediaQuery(size)
|
||||
|
||||
addVariant(
|
||||
screen,
|
||||
transformLastClasses(
|
||||
(className) => {
|
||||
return `${screen}${config('separator')}${className}`
|
||||
},
|
||||
{ wrap: () => postcss.atRule({ name: 'media', params: query }) }
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
...Object.fromEntries(
|
||||
Object.entries(corePlugins).map(([pluginName, plugin]) => {
|
||||
return [pluginName, plugin()]
|
||||
})
|
||||
),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue