Improve production build performance for the case of many small non-tailwind stylesheets (#4644)
* Improve `purge` performance in layers mode In layers mode, skip `purgecss` completely if source stylesheet does not have any tailwind layers. For the legacy codebases with a lot of non-tailwind stylesheets, it dratically improves the performance of the production build. * fix: purgecss should respect safelist.variables
This commit is contained in:
parent
bf482112a6
commit
2166b76c53
5 changed files with 108 additions and 34 deletions
21
package-lock.json
generated
21
package-lock.json
generated
|
|
@ -9,7 +9,6 @@
|
|||
"version": "2.2.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^4.0.3",
|
||||
"arg": "^5.0.0",
|
||||
"bytes": "^3.0.0",
|
||||
"chalk": "^4.1.1",
|
||||
|
|
@ -36,6 +35,7 @@
|
|||
"postcss-selector-parser": "^6.0.6",
|
||||
"postcss-value-parser": "^4.1.0",
|
||||
"pretty-hrtime": "^1.0.3",
|
||||
"purgecss": "^4.0.3",
|
||||
"quick-lru": "^5.1.1",
|
||||
"reduce-css-calc": "^2.1.8",
|
||||
"resolve": "^1.20.0",
|
||||
|
|
@ -1569,17 +1569,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@fullhuman/postcss-purgecss": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-4.0.3.tgz",
|
||||
"integrity": "sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==",
|
||||
"dependencies": {
|
||||
"purgecss": "^4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
|
|
@ -11507,14 +11496,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@fullhuman/postcss-purgecss": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-4.0.3.tgz",
|
||||
"integrity": "sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==",
|
||||
"requires": {
|
||||
"purgecss": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
"postcss": "^8.0.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^4.0.3",
|
||||
"purgecss": "^4.0.3",
|
||||
"arg": "^5.0.0",
|
||||
"bytes": "^3.0.0",
|
||||
"chalk": "^4.1.1",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"cssnano": "^4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullhuman/postcss-purgecss": "^3.1.3",
|
||||
"purgecss": "^4.0.3",
|
||||
"autoprefixer": "^9",
|
||||
"postcss": "^7",
|
||||
"postcss-functions": "^3",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash'
|
||||
import postcss from 'postcss'
|
||||
import purgecss from '@fullhuman/postcss-purgecss'
|
||||
import PurgeCSS, { defaultOptions, standardizeSafelist, mergeExtractorSelectors } from 'purgecss'
|
||||
import log from '../util/log'
|
||||
import htmlTags from 'html-tags'
|
||||
import path from 'path'
|
||||
|
|
@ -134,10 +134,11 @@ export default function purgeUnusedUtilities(config, configChanged, registerDepe
|
|||
registerDependency(parseDependency(fileOrGlob))
|
||||
}
|
||||
|
||||
let hasLayers = false
|
||||
|
||||
const mode = _.get(config, 'purge.mode', 'layers')
|
||||
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`.')
|
||||
}
|
||||
|
|
@ -164,6 +165,7 @@ export default function purgeUnusedUtilities(config, configChanged, registerDepe
|
|||
switch (comment.text.trim()) {
|
||||
case `tailwind start ${layer}`:
|
||||
comment.text = 'purgecss end ignore'
|
||||
hasLayers = true
|
||||
break
|
||||
case `tailwind end ${layer}`:
|
||||
comment.text = 'purgecss start ignore'
|
||||
|
|
@ -178,14 +180,44 @@ export default function purgeUnusedUtilities(config, configChanged, registerDepe
|
|||
css.append(postcss.comment({ text: 'purgecss end ignore' }))
|
||||
},
|
||||
removeTailwindMarkers,
|
||||
purgecss({
|
||||
defaultExtractor: (content) => {
|
||||
const transformer = getTransformer(config)
|
||||
return defaultExtractor(transformer(content))
|
||||
},
|
||||
extractors: fileSpecificExtractors,
|
||||
...purgeOptions,
|
||||
content,
|
||||
}),
|
||||
|
||||
async function (css) {
|
||||
if (mode === 'layers' && !hasLayers) {
|
||||
return
|
||||
}
|
||||
const purgeCSS = new PurgeCSS()
|
||||
purgeCSS.options = {
|
||||
...defaultOptions,
|
||||
|
||||
defaultExtractor: (content) => {
|
||||
const transformer = getTransformer(config)
|
||||
return defaultExtractor(transformer(content))
|
||||
},
|
||||
extractors: fileSpecificExtractors,
|
||||
...purgeOptions,
|
||||
safelist: standardizeSafelist(purgeOptions.safelist),
|
||||
}
|
||||
|
||||
if (purgeCSS.options.variables) {
|
||||
purgeCSS.variablesStructure.safelist = purgeCSS.options.safelist.variables || []
|
||||
}
|
||||
|
||||
const fileFormatContents = content.filter((o) => typeof o === 'string')
|
||||
const rawFormatContents = content.filter((o) => typeof o === 'object')
|
||||
|
||||
const cssFileSelectors = await purgeCSS.extractSelectorsFromFiles(
|
||||
fileFormatContents,
|
||||
purgeCSS.options.extractors
|
||||
)
|
||||
const cssRawSelectors = await purgeCSS.extractSelectorsFromString(
|
||||
rawFormatContents,
|
||||
purgeCSS.options.extractors
|
||||
)
|
||||
const cssSelectors = mergeExtractorSelectors(cssFileSelectors, cssRawSelectors)
|
||||
purgeCSS.walkThroughCSS(css, cssSelectors)
|
||||
if (purgeCSS.options.fontFace) purgeCSS.removeUnusedFontFaces()
|
||||
if (purgeCSS.options.keyframes) purgeCSS.removeUnusedKeyframes()
|
||||
if (purgeCSS.options.variables) purgeCSS.removeUnusedCSSVariables()
|
||||
},
|
||||
])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -639,6 +639,67 @@ test(
|
|||
})
|
||||
)
|
||||
|
||||
test('purges unused css variables in "all" mode', () => {
|
||||
return inProduction(
|
||||
suppressConsoleLogs(() => {
|
||||
return postcss([
|
||||
tailwind({
|
||||
...config,
|
||||
purge: {
|
||||
mode: 'all',
|
||||
content: [path.resolve(`${__dirname}/fixtures/**/*.html`)],
|
||||
options: {
|
||||
variables: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
])
|
||||
.process(
|
||||
`
|
||||
:root {
|
||||
--unused-var: 1;
|
||||
}
|
||||
`
|
||||
)
|
||||
.then((result) => {
|
||||
expect(result.css).not.toContain('--unused-var')
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('respects safelist.variables in "all" mode', () => {
|
||||
return inProduction(
|
||||
suppressConsoleLogs(() => {
|
||||
return postcss([
|
||||
tailwind({
|
||||
...config,
|
||||
purge: {
|
||||
mode: 'all',
|
||||
content: [path.resolve(`${__dirname}/fixtures/**/*.html`)],
|
||||
options: {
|
||||
variables: true,
|
||||
safelist: {
|
||||
variables: ['--unused-var'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
])
|
||||
.process(
|
||||
`
|
||||
:root {
|
||||
--unused-var: 1;
|
||||
}
|
||||
`
|
||||
)
|
||||
.then((result) => {
|
||||
expect(result.css).toContain('--unused-var')
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('element selectors are preserved by default', () => {
|
||||
return inProduction(
|
||||
suppressConsoleLogs(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue