Semantic-UI + PurgeCSS(postcss)
Hey everyone.
I am trying to optimize a very simple site that was bootstrapped using CRA. I am bad with CSS so I use Semantic UI React components and the semantic-ui-css package. My bundle size is quite large and includes a lot of unused CSS as reported by Lighthouse.
File sizes after gzip:
182.41 KB build\static\js\2.2c0cec5e.chunk.js
95.82 KB build\static\css\2.003b56fe.chunk.css
8.34 KB (-1 B) build\static\js\main.13de69e2.chunk.js
771 B build\static\js\runtime-main.2a146b8e.js
449 B build\static\css\main.6b845f7c.chunk.css
I'm currently trying to configure the purgecss postcss plugin via @craco/craco but too much styling is being removed. Here is my postcss.config.js which I basically copy pasted from Tailwind documentation that includes some regex. Obviously this regex will not work with Semantic so I was hoping someone in the community might either have regex that works with Semantic + purgecss (very bad with regex) or a different solution to remove unused CSS from Semantic in React.
const purgecss = require('@fullhuman/postcss-purgecss')({
// Specify the paths to all of the template files in your project
content: ['./public/**/*.html', './src/**/*.css', './src/**/*.js'],
// This is the function used to extract class names from your templates
defaultExtractor: (content) => {
// Capture as liberally as possible, including things like `h-(screen-1.5)`
const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [];
// Capture classes within other delimiters like .block(class="w-1/2") in Pug
const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || [];
return broadMatches.concat(innerMatches);
},
});
module.exports = {
plugins: [...(process.env.NODE_ENV === 'production' ? [purgecss] : [])],
};
1 comments · 75% upvoted · other discussions
I have a setup that might be what you're looking for. My app is CRA, Tailwind, Semantic UI, Styled Components, and config via Craco. We're also lazy loading for code splitting.
What I did was move the PurgeCSS config to
postcss.config.js:``` const cssnano = require('cssnano'); const postcssPresetEnv = require('postcss-preset-env'); const purgecss = require('@fullhuman/postcss-purgecss');
module.exports = () => ({ plugins: [ postcssPresetEnv({ stage: 3, features: { 'custom-properties': { preserve: true, fallback: true, }, }, autoprefixer: { flexbox: true, grid: false, }, }), cssnano({ preset: [ 'default', { discardComments: { removeAll: true, }, }, ], }), purgecss({ content: ['./src//*.html', './src//.js', './src//.jsx', './src//*.ts', './src//.tsx', './public/index.html'], css: ['./src/styles/tailwind.css'], // This is the function used to extract class names from your templates defaultExtractor: (content) => { // Capture as liberally as possible, including things like
h-(screen-1.5)const broadMatches = content.match(/[<>"'`\s][<>"'`\s:]/g) || [];], }); ```
Then load that config onto
craco.config.jsand add the PurgeCSS Webpack plugin:``` const { resolve } = require('path'); const { realpathSync } = require('fs'); const glob = require('glob');
const { POSTCSS_MODES } = require('@craco/craco'); const PurgecssPlugin = require('purgecss-webpack-plugin');
const appDirectory = realpathSync(process.cwd()); const resolveApp = (relativePath) => resolve(appDirectory, relativePath);
module.exports = { style: { postcss: { mode: POSTCSS_MODES.file, }, }, webpack: { plugins: [ new PurgecssPlugin({ paths: [resolveApp('public/index.html'), ...glob.sync(
${resolveApp('src')}/**/**/*, { nodir: true })], }), ], }, }; ```Then running
craco buildshould run PurgeCSS correctly for you.Fair warning, we came across this issue this week and I didn't attempt to fix it until today. So, although PurgeCSS is working as expected, there are still some optimizations to be done to these configs. And I think the PurgeCSS config on
postcss.config.jsis redundant and could be removed.Play around with this setup and see what works best for you.
Edit: Grammar.