I just ran a few tests and here are the results I'm getting:
Build time without postcss-purgecss:
76.02s
Build time with "@fullhuman/postcss-purgecss": "^1.4.2",
111.81s
Build time with "@fullhuman/postcss-purgecss": "^2.1.0",
385.60s
Here is the contents of my postcss.config.js
module.exports = {
plugins: [
process.env.NODE_ENV === 'production' ? require('@fullhuman/postcss-purgecss')({
content: [
'./public/**/*.html',
'./src/**/*.vue',
// custom
'./node_modules/vue-multiselect/src/Multiselect.vue',
// './node_modules/vue-tables-2/**/*',
'./node_modules/bootstrap-vue/src/components/**/*.js',
],
defaultExtractor: (content) => {
const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '');
return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || [];
},
whitelistPatterns: [
/-(leave|enter|appear)(|-(to|from|active))$/,
/^(?!cursor-move).+-move$/,
/^router-link(|-exact)-active$/,
// custom
/^multiselect/,
],
}) : '',
],
};
Any idea why this is happening and if there's a way to get reasonable build times using the latest version?
Many thanks
I can confirm this issue, our builds also went up by about a minute.
Our setup:
const TailwindExtractor = (content) => {
return content.match(/[\w-/:]*[\w-/:]/g) || []
}
const configurePurgeCss = () => {
let paths = []
// Configure whitelist paths
for (const [key, value] of Object.entries(settings.purgeCssConfig.paths)) {
paths.push(path.join(__dirname, value))
}
return {
paths: glob.sync(paths),
whitelistPatterns: [/-enter-active$/, /-leave-active$/, /-enter$/, /-leave-to$/, /gpay-button$/],
extractors: [
{
extractor: TailwindExtractor,
extensions: extensions: ['html', 'phtml', 'ts', 'js', 'vue'],
},
],
}
}
By timely coincidence, I was converting our purgecss step from webpack to postcss, and our build process has gone from a 1 minute to... well, I'm not sure as it's still building - over 10 minutes. If I remove purgecss from postcss, it's back to a reasonable time of around 50 seconds.
@TheDutchCoder @vesper8 Removing .js files (either explicitly or via glob pattern) brought me down to a reasonable time. Not sure if you'd experience the same. I can't recall why I was scanning js files for css classes to begin with.
Hey @chasegiunta @TheDutchCoder @vesper8, I'm not affiliated with this project, but I found myself debugging purgecss performance issues recently, and I believe I know how to improve the internal algorithms by a couple orders of magnitude, to be much faster than the 1.x performance. If you could share/fabricate some example inputs, it would help me validate the changes I have in mind.
@Ffloriel @jsnanigans Are you open to reviewing a PR?
I added a branch here. You will see a package named comparison. It will run PurgeCSS v1 and PurgeCSS v2 and print times in the console. Was thinking of going through the performance investigation too so I'll definitely be open to review a PR about it. Thanks!
i'd also be interested with how it improves here (tested against 1.4.0):
https://github.com/leeoniya/dropcss#performance
https://github.com/leeoniya/dropcss/tree/master/test/bench#readme
the source & corpus for the stress bench are in the second link, if interested.
@leeoniya yep, that's where I found it. Thanks for doing the bench in the first place btw. I took a quick look at dropcss when looking at it and it looks great!
From what I saw, using Set instead of arrays is doing a massive difference.
[ 'PurgeCSS v2', '3164ms', '18.91KB' ]
to
[ 'PurgeCSS v2', '401ms', '18.91KB' ]
@Ffloriel Can you keep working on the perf_investigation branch a bit, to make sure it builds in a fresh checkout the same way it builds on your machine? I can go into more detail if need be, but there seem to be a number of little problems, like the missing ./lib/vkbeautify import in index.ts.
I'm not complaining (I know this is brand-new code, and I am not blocked on it right now), but I think you might be able to fix these things faster than me. 馃檹
oh sorry, the file was gitignored. pushed it with the array-to-set change. Take a look and let me know what you found :) .
The bench is not a real life example though, but more of a stress test like @leeoniya mentioned here so it would still be useful to get another one.
@Ffloriel Using Sets is certainly part of the plan, but I hope you'll find my approach to be a little more involved/interesting than just switching data structures. To get the most out of a Set, for example, you need to avoid using it in ways that require it to behave like an array. Give me a day or two, and I think you'll see what I mean.
Sounds great!
Thanks for doing the bench in the first place btw. I took a quick look at dropcss when looking at it and it looks great!
and thanks for PurgeCSS! i was using it extensively before writing DropCSS. the fact that purgecss left behind unused CSS was the main motivation for my experimentation. the original idea and impl of DropCSS was a simple 60 LOC glue for what claimed to be fastest/best-in-class libs [1] [2] [3]. i figured this should yield the best perf and had no intention of writing custom html and css parsers D:, however, the rewrite ended up 8x faster because having access to the parser internals allowed for parse-tree reuse and other optimizations.
anyhoos, excited to see where this work goes!
[1] [fast-html-parser](https://www.npmjs.com/package/fast-html-parser)
[2] [css-tree](https://www.npmjs.com/package/css-tree)
[3] [css-select](https://www.npmjs.com/package/css-select)
Here's what I was able to do today: https://github.com/FullHuman/purgecss/pull/343
I'm optimistic about future performance work, but this PR seemed like a good stopping point for me. Thanks for everyone's help today.