From 4169bb1ac2d444c84a0866980fcbbc01fcfd4644 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Tue, 14 Jul 2020 20:53:18 -0400 Subject: [PATCH] Simplify implementation, remove unnecessary new features --- __tests__/tailwindAtRule.test.js | 226 ------------------------- src/lib/purgeUnusedStyles.js | 2 - src/lib/substituteResponsiveAtRules.js | 30 +--- src/lib/substituteTailwindAtRules.js | 34 ---- src/processTailwindFeatures.js | 9 + src/util/processPlugins.js | 22 ++- src/util/wrapWithVariants.js | 18 +- 7 files changed, 29 insertions(+), 312 deletions(-) delete mode 100644 __tests__/tailwindAtRule.test.js diff --git a/__tests__/tailwindAtRule.test.js b/__tests__/tailwindAtRule.test.js deleted file mode 100644 index 60085ae84..000000000 --- a/__tests__/tailwindAtRule.test.js +++ /dev/null @@ -1,226 +0,0 @@ -import postcss from 'postcss' -import plugin from '../src/lib/substituteTailwindAtRules' -import processPlugins from '../src/util/processPlugins' -import config from '../stubs/defaultConfig.stub.js' - -function run(input, opts = config) { - const plugins = [ - function({ addBase, addComponents, addUtilities }) { - addBase({ base: { property: 'test' } }) - addComponents({ '.components': { property: 'test' } }) - addUtilities({ '.utilities': { property: 'test' } }) - }, - ] - return postcss([plugin(opts, processPlugins(plugins, opts))]).process(input, { - from: undefined, - }) -} - -test('tailwind directives are replaced with their underlying CSS rules', () => { - const input = ` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - const output = ` - /* tailwind start base */ - base { property: test } - /* tailwind end base */ - /* tailwind start components */ - .components { property: test } - /* tailwind end components */ - /* tailwind start screens components */ - @screens components; - /* tailwind end screens components */ - /* tailwind start utilities */ - @variants { - .utilities { property: test } - } - /* tailwind end utilities */ - /* tailwind start screens utilities */ - @screens utilities; - /* tailwind end screens utilities */ - ` - - return run(input).then(result => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) -}) - -test('root-level component classes are not part of the components group', () => { - const input = ` - @tailwind base; - @tailwind components; - .btn { background: blue } - @tailwind utilities; - ` - - const output = ` - /* tailwind start base */ - base { property: test } - /* tailwind end base */ - - /* tailwind start components */ - .components { property: test } - /* tailwind end components */ - - /* tailwind start screens components */ - @screens components; - /* tailwind end screens components */ - - .btn { background: blue } - - /* tailwind start utilities */ - @variants { - .utilities { property: test } - } - /* tailwind end utilities */ - - /* tailwind start screens utilities */ - @screens utilities; - /* tailwind end screens utilities */ - ` - - return run(input).then(result => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) -}) - -test('nested rules are included in the corresponding bucket', () => { - const input = ` - @tailwind base { - html { font-size: 20px } - } - @tailwind components { - .btn { background: blue } - } - @tailwind utilities { - .tabular-nums { font-variant-numeric: tabular-nums } - } - ` - - const output = ` - /* tailwind start base */ - base { property: test } - html { font-size: 20px } - /* tailwind end base */ - - /* tailwind start components */ - .components { property: test } - .btn { background: blue } - /* tailwind end components */ - - /* tailwind start screens components */ - @screens components; - /* tailwind end screens components */ - - /* tailwind start utilities */ - @variants { - .utilities { property: test } - } - .tabular-nums { font-variant-numeric: tabular-nums } - /* tailwind end utilities */ - - /* tailwind start screens utilities */ - @screens utilities - /* tailwind end screens utilities */ - ` - - return run(input).then(result => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) -}) - -test('nested responsive component classes have the components argument added automatically', () => { - const input = ` - @tailwind base; - @tailwind components { - @responsive { - .btn { background: blue } - } - } - @tailwind utilities; - ` - - const output = ` - /* tailwind start base */ - base { property: test } - /* tailwind end base */ - - /* tailwind start components */ - .components { property: test } - @responsive components { - .btn { background: blue } - } - /* tailwind end components */ - - /* tailwind start screens components */ - @screens components; - /* tailwind end screens components */ - - /* tailwind start utilities */ - @variants { - .utilities { property: test } - } - /* tailwind end utilities */ - - /* tailwind start screens utilities */ - @screens utilities; - /* tailwind end screens utilities */ - ` - - return run(input).then(result => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) -}) - -test('nested responsive component classes authored using the variants syntax have the components argument added automatically', () => { - const input = ` - @tailwind base; - @tailwind components { - @variants responsive { - .btn { background: blue } - } - } - @tailwind utilities; - ` - - const output = ` - /* tailwind start base */ - base { property: test } - /* tailwind end base */ - - /* tailwind start components */ - .components { property: test } - @responsive components { - @variants { - .btn { background: blue } - } - } - /* tailwind end components */ - - /* tailwind start screens components */ - @screens components; - /* tailwind end screens components */ - - /* tailwind start utilities */ - @variants { - .utilities { property: test } - } - /* tailwind end utilities */ - - /* tailwind start screens utilities */ - @screens utilities; - /* tailwind end screens utilities */ - ` - - return run(input).then(result => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) -}) diff --git a/src/lib/purgeUnusedStyles.js b/src/lib/purgeUnusedStyles.js index 6da766447..75f096d25 100644 --- a/src/lib/purgeUnusedStyles.js +++ b/src/lib/purgeUnusedStyles.js @@ -11,11 +11,9 @@ function removeTailwindComments(css) { case 'tailwind start base': case 'tailwind start components': case 'tailwind start utilities': - case 'tailwind start screens': case 'tailwind end base': case 'tailwind end components': case 'tailwind end utilities': - case 'tailwind end screens': comment.remove() break default: diff --git a/src/lib/substituteResponsiveAtRules.js b/src/lib/substituteResponsiveAtRules.js index dc18645ae..7436d323e 100644 --- a/src/lib/substituteResponsiveAtRules.js +++ b/src/lib/substituteResponsiveAtRules.js @@ -10,16 +10,12 @@ export default function(config) { theme: { screens }, separator, } = config - const responsiveRules = { - components: postcss.root(), - utilities: postcss.root(), - } + const responsiveRules = postcss.root() const finalRules = [] css.walkAtRules('responsive', atRule => { - const bucket = atRule.params === 'components' ? 'components' : 'utilities' const nodes = atRule.nodes - responsiveRules[bucket].append(...cloneNodes(nodes)) + responsiveRules.append(...cloneNodes(nodes)) atRule.before(nodes) atRule.remove() }) @@ -30,10 +26,8 @@ export default function(config) { params: buildMediaQuery(screens[screen]), }) - mediaQuery.append(postcss.comment({ text: 'tailwind start components' })) - mediaQuery.append( - _.tap(responsiveRules.components.clone(), clonedRoot => { + _.tap(responsiveRules.clone(), clonedRoot => { clonedRoot.walkRules(rule => { rule.selectors = _.map(rule.selectors, selector => buildSelectorVariant(selector, screen, separator, message => { @@ -44,24 +38,6 @@ export default function(config) { }) ) - mediaQuery.append(postcss.comment({ text: 'tailwind end components' })) - - mediaQuery.append(postcss.comment({ text: 'tailwind start utilities' })) - - mediaQuery.append( - _.tap(responsiveRules.utilities.clone(), clonedRoot => { - clonedRoot.walkRules(rule => { - rule.selectors = _.map(rule.selectors, selector => - buildSelectorVariant(selector, screen, separator, message => { - throw rule.error(message) - }) - ) - }) - }) - ) - - mediaQuery.append(postcss.comment({ text: 'tailwind end utilities' })) - finalRules.push(mediaQuery) }) diff --git a/src/lib/substituteTailwindAtRules.js b/src/lib/substituteTailwindAtRules.js index b622a3678..e5fc0a4c4 100644 --- a/src/lib/substituteTailwindAtRules.js +++ b/src/lib/substituteTailwindAtRules.js @@ -49,31 +49,6 @@ export default function( let includesScreensExplicitly = false - function hasChildren(atRule) { - return atRule.nodes !== undefined && atRule.nodes.length > 0 - } - - function extractChildren(atRule, bucket) { - if (hasChildren(atRule)) { - atRule.walkAtRules('variants', variantsAtRule => { - const params = postcss.list.comma(variantsAtRule.params) - if (params.includes('responsive')) { - variantsAtRule.params = params.filter(p => p !== 'responsive').join(', ') - variantsAtRule.before( - postcss.atRule({ name: 'responsive', nodes: [variantsAtRule.clone()] }) - ) - variantsAtRule.remove() - } - }) - - atRule.walkAtRules('responsive', responsiveAtRule => { - responsiveAtRule.params = bucket - }) - - atRule.before(atRule.nodes) - } - } - css.walkAtRules('tailwind', atRule => { if (atRule.params === 'preflight') { // prettier-ignore @@ -81,26 +56,17 @@ export default function( } if (atRule.params === 'base') { - atRule.before(postcss.comment({ text: 'tailwind start base' })) atRule.before(updateSource(pluginBase, atRule.source)) - extractChildren(atRule, 'base') - atRule.before(postcss.comment({ text: 'tailwind end base' })) atRule.remove() } if (atRule.params === 'components') { - atRule.before(postcss.comment({ text: 'tailwind start components' })) atRule.before(updateSource(pluginComponents, atRule.source)) - extractChildren(atRule, 'components') - atRule.before(postcss.comment({ text: 'tailwind end components' })) atRule.remove() } if (atRule.params === 'utilities') { - atRule.before(postcss.comment({ text: 'tailwind start utilities' })) atRule.before(updateSource(pluginUtilities, atRule.source)) - extractChildren(atRule, 'utilities') - atRule.before(postcss.comment({ text: 'tailwind end utilities' })) atRule.remove() } }) diff --git a/src/processTailwindFeatures.js b/src/processTailwindFeatures.js index 294a8c5d7..a87a1e8c8 100644 --- a/src/processTailwindFeatures.js +++ b/src/processTailwindFeatures.js @@ -24,6 +24,15 @@ export default function(getConfig) { substituteResponsiveAtRules(config), substituteScreenAtRules(config), substituteClassApplyAtRules(config, processedPlugins.utilities), + function(css) { + css.walkAtRules('bucket', atRule => { + const bucket = atRule.params + atRule.before(postcss.comment({ text: `tailwind start ${bucket}` })) + atRule.before(atRule.nodes) + atRule.before(postcss.comment({ text: `tailwind end ${bucket}` })) + atRule.remove() + }) + }, purgeUnusedStyles(config), ]).process(css, { from: _.get(css, 'source.input.file') }) } diff --git a/src/util/processPlugins.js b/src/util/processPlugins.js index 98263a65f..088024f96 100644 --- a/src/util/processPlugins.js +++ b/src/util/processPlugins.js @@ -8,6 +8,7 @@ import generateVariantFunction from '../util/generateVariantFunction' import parseObjectStyles from '../util/parseObjectStyles' import prefixSelector from '../util/prefixSelector' import wrapWithVariants from '../util/wrapWithVariants' +import cloneNodes from '../util/cloneNodes' import increaseSpecificity from '../util/increaseSpecificity' import selectorParser from 'postcss-selector-parser' @@ -27,6 +28,15 @@ function containsClass(value) { }).transformSync(value) } +function wrapWithBucket(rules, bucket) { + return postcss + .atRule({ + name: 'bucket', + params: bucket, + }) + .append(cloneNodes(Array.isArray(rules) ? rules : [rules])) +} + export default function(plugins, config) { const pluginBaseStyles = [] const pluginComponents = [] @@ -108,7 +118,9 @@ export default function(plugins, config) { } }) - pluginUtilities.push(wrapWithVariants(styles.nodes, options.variants)) + pluginUtilities.push( + wrapWithVariants(wrapWithBucket(styles.nodes, 'utilities'), options.variants) + ) }, addComponents: (components, options) => { const defaultOptions = { variants: [], respectPrefix: true } @@ -125,11 +137,9 @@ export default function(plugins, config) { } }) - if (options.variants.length > 0) { - pluginComponents.push(wrapWithVariants(styles.nodes, options.variants, 'components')) - } else { - pluginComponents.push(...styles.nodes) - } + pluginComponents.push( + wrapWithVariants(wrapWithBucket(styles.nodes, 'components'), options.variants) + ) }, addBase: baseStyles => { pluginBaseStyles.push(...parseStyles(baseStyles)) diff --git a/src/util/wrapWithVariants.js b/src/util/wrapWithVariants.js index 3dc727e27..4c1fcf9d3 100644 --- a/src/util/wrapWithVariants.js +++ b/src/util/wrapWithVariants.js @@ -1,23 +1,7 @@ import postcss from 'postcss' import cloneNodes from './cloneNodes' -export default function wrapWithVariants(rules, variants, bucket = 'utilities') { - if (bucket === 'components' && variants.includes('responsive')) { - return postcss - .atRule({ - name: 'responsive', - params: 'components', - }) - .append( - postcss - .atRule({ - name: 'variants', - params: variants.filter(v => v !== 'responsive').join(', '), - }) - .append(cloneNodes(Array.isArray(rules) ? rules : [rules])) - ) - } - +export default function wrapWithVariants(rules, variants) { return postcss .atRule({ name: 'variants',