Simplify implementation, remove unnecessary new features

This commit is contained in:
Adam Wathan 2020-07-14 20:53:18 -04:00
parent fc1d4c4cb1
commit 4169bb1ac2
7 changed files with 29 additions and 312 deletions

View file

@ -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)
})
})

View file

@ -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:

View file

@ -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)
})

View file

@ -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()
}
})

View file

@ -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') })
}

View file

@ -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))

View file

@ -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',