Copy
You're reading the Ruby/Rails performance newsletter by Speedshop.

A long-time frontend performance drag is dead with the combination of PurgeCSS and HTTP/2

When I started doing Rails performance work in 2016, one common scenario played out at client after client. The app, which was probably 3-5 years old, suffered from poor frontend performance partly because it required 300kb-500kb of CSS on initial load. This CSS file had slowly grown in size over the years until it became a massive, terrible, awful hairball of a mess!

CSS is an important resource to keep under control in terms of size because of the extremely important place it occupies during a page render. It's usually the first thing we end up downloading, meaning that it's filesize impacts bandwidth consumption during a pretty important period (right after the HTML has downloaded, but before the page has rendered).

Of course, CSS, being how we describe how our pages look, must be downloaded before we can show anything to the user. However, it isn't necessarily always on our "critical path" - often, Javascript resources take far longer to download, compile and execute than CSS, so CSS is often not "on the critical path". However, it often has a major impact on page rendering even in these cases, because CSS and JS will often be downloaded at the same time, meaning that big CSS files can slow down the JS download, which in turn lengthens our critical path and increases page load time.

However, in the last few years, two tools have emerged which make this old problem pretty much obsolete.

First, we have PurgeCSS (via Webpacker). PurgeCSS simply compares the CSS selectors in your stylesheets with your actual views, and then removes any selectors and rules which cannot be applied because they don't match anything. It's a simple change, but it eliminates both unused parts of CSS frameworks and plugins, and unused "cruft" code which has accumulated in your codebase from old features, etc. I was shocked at how effective this was when I was trying it out with Tailwind, but it works quite well with any application or framework. GoRails has a good tutorial. The only caveat is that PurgeCSS may be difficult to apply to existing/large projects, because it can be hard to be sure that PurgeCSS is accurately seeing all of your existing views: if it misses some HTML somewhere, it will purge out CSS which is actually needed.

Second, is HTTP/2. HTTP/2 makes the "unbundling" of assets pretty much free, which allows us to split our CSS into many smaller "chunks", allowing for better HTTP caching performance and smaller filesizes, because a user only needs to download the CSS required for a particular page.

HTTP/2 makes unbundling cheap because all files on a given domain are downloaded over a single connection. In the Bad Old Days of HTTP/1, shipping CSS as many small files was bad because you could download about 6 files at a time, and these individual TCP connections couldn't co-ordinate with each other, leading to inefficient bandwidth usage. In HTTP/2, with one connection per origin, we can efficiently and quickly download as many files as required from a domain. Splitting CSS into many different files means that they can be cached by your CDN separately: for example, a common scheme is to split your CSS into two bundles, a vendor bundle for frameworks/plugins, and an app bundle for all the CSS you and your team wrote. App CSS tends to change more often than vendor CSS, so that way their caches can expire at different times, meaning a higher overall percentage of cached responses. Swell!

Second, we can "bundle" only the CSS needed for particular pages quite easily and in a very granular way. You might bundle your CSS, for example, like:
  • tailwind.css, for all of your Tailwind-related framework CSS.
  • calendar_plugin.css, for some CSS related to a calendar widget you use.
  • frontend_design_elements.css, app-related CSS used on your "customer facing" pages
  • users_controller.css, css you use specifically for this controller.
...and so on. You may have a dozen or so CSS files on each page, with perhaps dozens more not required by any particular page. This keeps your CSS download sizes as small as the have to be, but without a perf penalty!

So, I think in the future I'll have less to do with clients when working with CSS, as both of these practices start to become the "new default" across apps. That's great - here's to progress!

Until next week,

-Nate
You can share this email with this permalink: https://mailchi.mp/railsspeed/purgecss-and-http2-means-css-bloat-is-dead?e=[UNIQID]

Copyright © 2021 Nate Berkopec, All rights reserved.


Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list.