From ed61821e42fca95b6227c2de59d10cd3069e516b Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 24 Sep 2021 14:27:42 -0400 Subject: [PATCH] Properly optimize universal defaults for legacy pseudo-element syntax (#5594) --- src/lib/resolveDefaultsAtRules.js | 13 ++++- tests/resolve-defaults-at-rules.test.js | 75 +++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/lib/resolveDefaultsAtRules.js b/src/lib/resolveDefaultsAtRules.js index e8c1399b9..f83e28ce1 100644 --- a/src/lib/resolveDefaultsAtRules.js +++ b/src/lib/resolveDefaultsAtRules.js @@ -2,6 +2,17 @@ import postcss from 'postcss' import selectorParser from 'postcss-selector-parser' import { flagEnabled } from '../featureFlags' +function isPseudoElement(n) { + if (n.type !== 'pseudo') { + return false + } + + return ( + n.value.startsWith('::') || + [':before', ':after', ':first-line', ':first-letter'].includes(n.value) + ) +} + function minimumImpactSelector(nodes) { let rest = nodes // Keep all pseudo & combinator types (:not([hidden]) ~ :not([hidden])) @@ -9,7 +20,7 @@ function minimumImpactSelector(nodes) { // Remove leading pseudo's (:hover, :focus, ...) .filter((n, idx, all) => { // Keep pseudo elements - if (n.type === 'pseudo' && n.value.startsWith('::')) return true + if (isPseudoElement(n)) return true if (idx === 0 && n.type === 'pseudo') return false if (idx > 0 && n.type === 'pseudo' && all[idx - 1].type === 'pseudo') return false diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 6f250bc6b..e4d29af02 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -391,6 +391,81 @@ test('with apply', async () => { }) }) +test('legacy pseudo-element syntax is supported', async () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + + .a:before { + content: ''; + @apply rotate-45; + } + + .b:after { + content: ''; + @apply rotate-3; + } + + .c:first-line { + content: ''; + @apply rotate-1; + } + + .d:first-letter { + content: ''; + @apply rotate-6; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a:before, + .b:after, + .c:first-line, + .d:first-letter { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + /* --- */ + .a:before { + content: ''; + --tw-rotate: 45deg; + transform: var(--tw-transform); + } + .b:after { + content: ''; + --tw-rotate: 3deg; + transform: var(--tw-transform); + } + .c:first-line { + content: ''; + --tw-rotate: 1deg; + transform: var(--tw-transform); + } + .d:first-letter { + content: ''; + --tw-rotate: 6deg; + transform: var(--tw-transform); + } + `) + }) +}) + test('with borders', async () => { let config = { content: [{ raw: html`
` }],