Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Optimize universal selector usage by inlining only the relevant selectors #4850

Merged
merged 13 commits into from Jul 1, 2021
2 changes: 1 addition & 1 deletion jest/customMatchers.js
Expand Up @@ -102,7 +102,7 @@ expect.extend({
// This is probably naive but it's fast and works well enough.
toMatchFormattedCss(received, argument) {
function format(input) {
return prettier.format(input, {
return prettier.format(input.replace(/\n/g, ''), {
parser: 'css',
printWidth: 100,
})
Expand Down
69 changes: 69 additions & 0 deletions src/jit/lib/resolveDefaultsAtRules.js
@@ -0,0 +1,69 @@
import postcss from 'postcss'
import selectorParser from 'postcss-selector-parser'

let elementSelectorParser = selectorParser((selectors) => {
return selectors.map((s) => {
return s
.split((n) => n.type === 'combinator')
.pop()
.filter((n) => n.type !== 'pseudo' || n.value.startsWith('::'))
.join('')
.trim()
})
})

let cache = new Map()

function extractElementSelector(selector) {
if (!cache.has(selector)) {
cache.set(selector, elementSelectorParser.transformSync(selector))
}

return cache.get(selector)
}

export default function resolveDefaultsAtRules() {
return (root) => {
let variableNodeMap = new Map()
let universals = new Set()

root.walkAtRules('defaults', (rule) => {
if (rule.nodes.length > 0) {
universals.add(rule)
return
}

let variable = rule.params
if (!variableNodeMap.has(variable)) {
variableNodeMap.set(variable, new Set())
}

variableNodeMap.get(variable).add(rule.parent)

rule.remove()
})

for (let universal of universals) {
let selectors = new Set()

let rules = variableNodeMap.get(universal.params) ?? []

for (let rule of rules) {
for (let selector of extractElementSelector(rule.selector)) {
selectors.add(selector)
}
}

if (selectors.size === 0) {
universal.remove()
continue
}

let universalRule = postcss.rule()
universalRule.selectors = [...selectors]
universalRule.append(universal.nodes)
universal.before(universalRule)
universal.remove()
}
}
}
2 changes: 2 additions & 0 deletions src/jit/processTailwindFeatures.js
Expand Up @@ -3,6 +3,7 @@ import expandTailwindAtRules from './lib/expandTailwindAtRules'
import expandApplyAtRules from './lib/expandApplyAtRules'
import evaluateTailwindFunctions from '../lib/evaluateTailwindFunctions'
import substituteScreenAtRules from '../lib/substituteScreenAtRules'
import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules'
import collapseAdjacentRules from './lib/collapseAdjacentRules'
import { createContext } from './lib/setupContextUtils'
import log from '../util/log'
Expand Down Expand Up @@ -45,6 +46,7 @@ export default function processTailwindFeatures(setupContext) {
expandApplyAtRules(context)(root, result)
evaluateTailwindFunctions(context)(root, result)
substituteScreenAtRules(context)(root, result)
resolveDefaultsAtRules(context)(root, result)
collapseAdjacentRules(context)(root, result)
}
}
7 changes: 6 additions & 1 deletion src/plugins/backdropBlur.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-blur': (value) => {
return {
'--tw-backdrop-blur': `blur(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropBrightness.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-brightness': (value) => {
return {
'--tw-backdrop-brightness': `brightness(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropContrast.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-contrast': (value) => {
return {
'--tw-backdrop-contrast': `contrast(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 5 additions & 2 deletions src/plugins/backdropFilter.js
Expand Up @@ -2,7 +2,7 @@ export default function () {
return function ({ config, addBase, addUtilities, variants }) {
if (config('mode') === 'jit') {
addBase({
'*, ::before, ::after': {
'@defaults backdrop-filter': {
'--tw-backdrop-blur': 'var(--tw-empty,/*!*/ /*!*/)',
'--tw-backdrop-brightness': 'var(--tw-empty,/*!*/ /*!*/)',
'--tw-backdrop-contrast': 'var(--tw-empty,/*!*/ /*!*/)',
Expand All @@ -27,7 +27,10 @@ export default function () {
})
addUtilities(
{
'.backdrop-filter': { 'backdrop-filter': 'var(--tw-backdrop-filter)' },
'.backdrop-filter': {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
},
'.backdrop-filter-none': { 'backdrop-filter': 'none' },
},
variants('backdropFilter')
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropGrayscale.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-grayscale': (value) => {
return {
'--tw-backdrop-grayscale': `grayscale(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropHueRotate.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-hue-rotate': (value) => {
return {
'--tw-backdrop-hue-rotate': `hue-rotate(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropInvert.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-invert': (value) => {
return {
'--tw-backdrop-invert': `invert(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropOpacity.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-opacity': (value) => {
return {
'--tw-backdrop-opacity': `opacity(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropSaturate.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-saturate': (value) => {
return {
'--tw-backdrop-saturate': `saturate(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/backdropSepia.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
'backdrop-sepia': (value) => {
return {
'--tw-backdrop-sepia': `sepia(${value})`,
...(config('mode') === 'jit' ? { 'backdrop-filter': 'var(--tw-backdrop-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults backdrop-filter': {},
'backdrop-filter': 'var(--tw-backdrop-filter)',
}
: {}),
}
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/blur.js
Expand Up @@ -5,7 +5,12 @@ export default function () {
blur: (value) => {
return {
'--tw-blur': `blur(${value})`,
...(config('mode') === 'jit' ? { filter: 'var(--tw-filter)' } : {}),
...(config('mode') === 'jit'
? {
'@defaults filter': {},
filter: 'var(--tw-filter)',
}
: {}),
}
},
},
Expand Down
44 changes: 31 additions & 13 deletions src/plugins/borderColor.js
Expand Up @@ -3,20 +3,38 @@ import withAlphaVariable from '../util/withAlphaVariable'

export default function () {
return function ({ config, addBase, matchUtilities, theme, variants, corePlugins }) {
if (!corePlugins('borderOpacity')) {
addBase({
'*, ::before, ::after': {
'border-color': theme('borderColor.DEFAULT', 'currentColor'),
},
})
if (config('mode') === 'jit') {
if (!corePlugins('borderOpacity')) {
addBase({
'@defaults border-width': {
'border-color': theme('borderColor.DEFAULT', 'currentColor'),
},
})
} else {
addBase({
'@defaults border-width': withAlphaVariable({
color: theme('borderColor.DEFAULT', 'currentColor'),
property: 'border-color',
variable: '--tw-border-opacity',
}),
})
}
} else {
addBase({
'*, ::before, ::after': withAlphaVariable({
color: theme('borderColor.DEFAULT', 'currentColor'),
property: 'border-color',
variable: '--tw-border-opacity',
}),
})
if (!corePlugins('borderOpacity')) {
addBase({
'*, ::before, ::after': {
'border-color': theme('borderColor.DEFAULT', 'currentColor'),
},
})
} else {
addBase({
'*, ::before, ::after': withAlphaVariable({
color: theme('borderColor.DEFAULT', 'currentColor'),
property: 'border-color',
variable: '--tw-border-opacity',
}),
})
}
}

matchUtilities(
Expand Down
44 changes: 31 additions & 13 deletions src/plugins/borderWidth.js
Expand Up @@ -2,17 +2,35 @@ import { asLength } from '../util/pluginUtils'
import createUtilityPlugin from '../util/createUtilityPlugin'

export default function () {
return createUtilityPlugin(
'borderWidth',
[
['border', ['border-width']],
[
['border-t', ['border-top-width']],
['border-r', ['border-right-width']],
['border-b', ['border-bottom-width']],
['border-l', ['border-left-width']],
],
],
{ resolveArbitraryValue: asLength }
)
return function (helpers) {
if (helpers.config('mode') === 'jit') {
createUtilityPlugin(
'borderWidth',
[
['border', [['@defaults border-width', {}], 'border-width']],
[
['border-t', [['@defaults border-width', {}], 'border-top-width']],
['border-r', [['@defaults border-width', {}], 'border-right-width']],
['border-b', [['@defaults border-width', {}], 'border-bottom-width']],
['border-l', [['@defaults border-width', {}], 'border-left-width']],
],
],
{ resolveArbitraryValue: asLength }
)(helpers)
} else {
createUtilityPlugin(
'borderWidth',
[
['border', ['border-width']],
[
['border-t', ['border-top-width']],
['border-r', ['border-right-width']],
['border-b', ['border-bottom-width']],
['border-l', ['border-left-width']],
],
],
{ resolveArbitraryValue: asLength }
)(helpers)
}
}
}