Skip to content

Purge unused CSS utilities #1000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Oct 12, 2021
Merged

Purge unused CSS utilities #1000

merged 19 commits into from
Oct 12, 2021

Conversation

shawnbot
Copy link
Member

@shawnbot shawnbot commented Aug 30, 2021

This PR introduces PurgeCSS to our CSS build process to "purge" unused selectors from our stylesheets. Here's how it works:

  • Our PurgeCSS config lives in purgecss.config.js so that we can use the same options for both the CLI and the postcss plugin. There are two options that do all the work for us:
    1. rejected: true tells PurgeCSS to collect and report information about the list of rejected ("purged") CSS when it runs
    2. content: [...] lists paths (mostly globs) where it should look for HTML elements, attributes, and any "token" that looks like a class name. Currently I have this set to pull in:
      • templates/**/*.{twig,html} to match all templates in this Drupal theme
      • src/**/*.js to match class names that we may use to either query or add/remove in our JavaScript
      • ../../../modules/custom/**/*.{html,inc,php,theme,twig} to match files that might contain classes in any of our custom modules
  • postcss-purgecss takes the options and from our config, reads all of the files in the content globs listed above, and "rejects" selectors that don't match anything found in the content
  • A custom postcss reporter takes the rejected messages for each file, generates a {filename}.css.purged.json alongside each {filename}.css, and outputs some useful info to the console

So now, when you run npm run build-css you should see some helpful output like this:

Processing src/sass/critical.css...
Processing src/sass/editorial.css...
Processing src/sass/utilities.css...
Processing src/sass/drupal.css...
🙈 purgecss did not process dist/css/critical.css (source: src/sass/critical.css)
🔥 purged 14 un-referenced selectors from dist/css/drupal.css
   see dist/css/drupal.css.purged.json for the full list
🔥 purged 3093 un-referenced selectors from dist/css/utilities.css
   see dist/css/utilities.css.purged.json for the full list
🙈 purgecss did not process dist/css/editorial.css (source: src/sass/editorial.css)
Finished src/sass/critical.css in 2.4 s
Finished src/sass/drupal.css in 2.39 s
Finished src/sass/utilities.css in 2.39 s
Finished src/sass/editorial.css in 2.39 s

I've added a new utilities.css bundle that imports dist/css/utilities.css from the design system and purges utilities that aren't referenced in any of our templates. That specific @import rule is handled by postcss-import, which I've configured to only inline imports whose URL ends in .css, so that it doesn't conflict with the Sass imports.

Testing

I think this is a combination of gut checking the rejected selector lists and QA, but in a nutshell: We need to make sure that this isn't rejecting the wrong selectors.

If there's CSS that's being purged from bundles besides utilities.css (which is basically purge-able by design because it includes every permutation of every utility class), then we should be deleting the corresponding (S)CSS! (Fun fact: creating this PR was actually how I discovered that all of the CSS in our twitter.css bundle was irrelevant, which allowed it to be deleted in #998 💪 )

Disabling PurgeCSS

If it looks like PurgeCSS is over-aggressively purging selectors that are used, we'll need to do one or both of the following:

  1. Add purgecess ignore comments to CSS that we want to prevent from being purged. You can run scripts/add-purgecss-comments on one or more files to safe-list them entirely:

    scripts/add-purgecss-comments path/to/foo.scss path/to/bar.scss
  2. Add safe lists to our PurgeCSS config to prevent specific selectors from being purged.

@shawnbot

This comment has been minimized.

@aekong
Copy link
Collaborator

aekong commented Aug 30, 2021

thanks for doing this!

we may want to test the admin theme too.

also, you can see some quick screenshots of where there might be some issues: http://ronswanbot.herokuapp.com/ghost-inspector/suite-results/612d26c69bed453ad10dee52

@shawnbot
Copy link
Member Author

@aekong Yeah, I expected there to be issues on the first run. I'm trying to walk that back by safe-listing all of the SCSS partials with /* purgecss start ignore */ and /* purgecss end ignore */ comments around all the CSS. 🤞

@shawnbot
Copy link
Member Author

Lookin better with all of the Sass safe listed!

image

@shawnbot
Copy link
Member Author

I could be wrong, but it looks like this PR might shave about 13K off our CSS bundle (according to Lighthouse):

Transfer size Potential savings
sf.gov 68.9 K 64.6 K
this PR 56.1 K 51.9 K
delta 12.8 K 12.7 K

@shawnbot shawnbot requested review from shadcn, minnur and zakiya August 30, 2021 21:10
@shawnbot shawnbot marked this pull request as ready for review August 30, 2021 21:10
Comment on lines +7 to +9
require('postcss-import')({
filter: path => path.endsWith('.css')
}),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we inline @import statements, but only for paths that end in .css (i.e., not Sass).

@aekong
Copy link
Collaborator

aekong commented Aug 31, 2021

looks pretty good!

did notice one thing based on the purged json report:

{
  "selectors": [
    ".views--meetings .views-row article .article--teaser__title",
     // ... more .views--meetings purged classes
  ]
}

It looks like the safelist purge comment was already added to web/themes/custom/sfgovpl/src/sass/view/_view-meetings.scss, so not sure why the upcoming meetings view listing is off:

test pr-1000
Screen Shot 2021-08-31 at 12 05 45 AM Screen Shot 2021-08-31 at 12 05 53 AM

I thought it might be that the twig templates set the classnames in an array and then output them in a twig expression, but that's happening everywhere else, too,so not sure why these selectors are being purged.

@shawnbot
Copy link
Member Author

@aekong

did notice one thing based on the purged json report:

{
  "selectors": [
    ".views--meetings .views-row article .article--teaser__title",
     // ... more .views--meetings purged classes
  ]
}

I think this is because of the way that postcss hoists @import rules (check this comment for more info). I updated the scripts/add-purgecss-comments script in 75e24f8 and re-ran it on the files in question in dfb4972, and that seems to have completely safe-listed them:

🙈 purgecss did not process dist/css/editorial.css (source: src/sass/editorial.css)
🙈 purgecss did not process dist/css/critical.css (source: src/sass/critical.css)
🙈 purgecss did not process dist/css/drupal.css (source: src/sass/drupal.css)
🔥 purged 3093 un-referenced selectors from dist/css/utilities.css
   see dist/css/utilities.css.purged.json for the full list

I know it might seem silly to add a bunch of tooling around safe-listing entire files, but it's one thing we did at GitHub that ended up being extremely helpful before big refactors.

@shawnbot shawnbot removed request for zakiya and minnur September 1, 2021 22:54
@aekong
Copy link
Collaborator

aekong commented Sep 17, 2021

i'm good for this to get merged in, thanks for putting it together! do you think we should add the bit from your pr description:

Disabling PurgeCSS
If it looks like PurgeCSS is over-aggressively purging selectors that are used, we'll need to do one or both of the following:

Add purgecess ignore comments to CSS that we want to prevent from being purged. You can run scripts/add-purgecss-comments on one or more files to safe-list them entirely:

scripts/add-purgecss-comments path/to/foo.scss path/to/bar.scss
Add safe lists to our PurgeCSS config to prevent specific selectors from being purged.

to the readme? I'm hoping we'll steer clear of writing too much more custom css and hopefully start using more of the design system utilities, but while the design system matures we'll probaby have to, and it'd be good to have the heads up when building locally

* Update README.md

adding notes from helpful pr description

* add links

* update purgecss code links

Co-authored-by: Shawn Allen <[email protected]>
@shawnbot shawnbot merged commit a1d9b70 into develop Oct 12, 2021
@shawnbot shawnbot deleted the purgecss branch October 12, 2021 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants