mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
* Add failing test for purge preserving element selectors when `defaultExtractor` is overridden * `preserveHtmlElements` works with user-defined purge extractors
122 lines
3.9 KiB
JavaScript
122 lines
3.9 KiB
JavaScript
import _ from 'lodash'
|
|
import postcss from 'postcss'
|
|
import purgecss from '@fullhuman/postcss-purgecss'
|
|
import log from '../util/log'
|
|
import htmlTags from 'html-tags'
|
|
|
|
function removeTailwindMarkers(css) {
|
|
css.walkAtRules('tailwind', (rule) => rule.remove())
|
|
css.walkComments((comment) => {
|
|
switch (comment.text.trim()) {
|
|
case 'tailwind start base':
|
|
case 'tailwind end base':
|
|
case 'tailwind start components':
|
|
case 'tailwind start utilities':
|
|
case 'tailwind end components':
|
|
case 'tailwind end utilities':
|
|
comment.remove()
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
})
|
|
}
|
|
|
|
export function tailwindExtractor(content) {
|
|
// Capture as liberally as possible, including things like `h-(screen-1.5)`
|
|
const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []
|
|
const broadMatchesWithoutTrailingSlash = broadMatches.map((match) => _.trimEnd(match, '\\'))
|
|
|
|
// Capture classes within other delimiters like .block(class="w-1/2") in Pug
|
|
const innerMatches = content.match(/[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g) || []
|
|
|
|
return broadMatches.concat(broadMatchesWithoutTrailingSlash).concat(innerMatches)
|
|
}
|
|
|
|
export default function purgeUnusedUtilities(config, configChanged) {
|
|
const purgeEnabled = _.get(
|
|
config,
|
|
'purge.enabled',
|
|
config.purge !== false && config.purge !== undefined && process.env.NODE_ENV === 'production'
|
|
)
|
|
|
|
if (!purgeEnabled) {
|
|
return removeTailwindMarkers
|
|
}
|
|
|
|
// Skip if `purge: []` since that's part of the default config
|
|
if (Array.isArray(config.purge) && config.purge.length === 0) {
|
|
if (configChanged) {
|
|
log.warn([
|
|
'Tailwind is not purging unused styles because no template paths have been provided.',
|
|
'If you have manually configured PurgeCSS outside of Tailwind or are deliberately not removing unused styles, set `purge: false` in your Tailwind config file to silence this warning.',
|
|
'https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css',
|
|
])
|
|
}
|
|
|
|
return removeTailwindMarkers
|
|
}
|
|
|
|
const { defaultExtractor, ...purgeOptions } = config.purge.options || {}
|
|
|
|
return postcss([
|
|
function (css) {
|
|
const mode = _.get(config, 'purge.mode', 'layers')
|
|
|
|
if (!['all', 'layers'].includes(mode)) {
|
|
throw new Error('Purge `mode` must be one of `layers` or `all`.')
|
|
}
|
|
|
|
if (mode === 'all') {
|
|
return
|
|
}
|
|
|
|
const layers = _.get(config, 'purge.layers', ['base', 'components', 'utilities'])
|
|
|
|
css.walkComments((comment) => {
|
|
switch (comment.text.trim()) {
|
|
case `purgecss start ignore`:
|
|
comment.before(postcss.comment({ text: 'purgecss end ignore' }))
|
|
break
|
|
case `purgecss end ignore`:
|
|
comment.before(postcss.comment({ text: 'purgecss end ignore' }))
|
|
comment.text = 'purgecss start ignore'
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
layers.forEach((layer) => {
|
|
switch (comment.text.trim()) {
|
|
case `tailwind start ${layer}`:
|
|
comment.text = 'purgecss end ignore'
|
|
break
|
|
case `tailwind end ${layer}`:
|
|
comment.text = 'purgecss start ignore'
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
})
|
|
})
|
|
|
|
css.prepend(postcss.comment({ text: 'purgecss start ignore' }))
|
|
css.append(postcss.comment({ text: 'purgecss end ignore' }))
|
|
},
|
|
removeTailwindMarkers,
|
|
purgecss({
|
|
content: Array.isArray(config.purge) ? config.purge : config.purge.content,
|
|
defaultExtractor: (content) => {
|
|
const extractor = defaultExtractor || tailwindExtractor
|
|
const preserved = [...extractor(content)]
|
|
|
|
if (_.get(config, 'purge.preserveHtmlElements', true)) {
|
|
preserved.push(...htmlTags)
|
|
}
|
|
|
|
return preserved
|
|
},
|
|
...purgeOptions,
|
|
}),
|
|
])
|
|
}
|