Tree Shaking Bootstrap

Bootstrap is a comprehensive CSS toolkit that includes hundreds of components. But chances are, you’re only using a fraction of those.

If you choose to compile Bootstrap yourself, you get the option to exclude parts of the framework — not using tables, don’t include the styling for them. It’s simple, but easy to get wrong.

Even if you do this (and many don’t), you’re still including lots of styles you won’t use. If you need columns, you have to include the entire thing: but you definitely won’t be using col-xs-11.

For those of us with an entirely React — or otherwise JavaScript — codebase, we can do something about it.

You might have heard about CSS Modules. The concept is simple. Import CSS files in your JavaScript, and it will export the class names used within the file. It works just like below.

Building upon CSS Modules, there is ES CSS Modules. This is the same concept, except that it looks at your codebase and works out what styles you actually use. It’ll use this information to strip out anything that isn’t used, giving you tiny CSS files. This is known as tree shaking.

Step 1: Setting up Bootstrap

We just need to quickly setup Bootstrap. We’ll be using Bootstrap 4 alpha, because this is a demo project, and I like to live dangerously. I’ve just downloaded the SCSS files and put them in a directory called scss, and then made a gulp task to compile them.

Bam! Bootstrap compiled. However, there is one caveat: ES CSS Modules requires the class names to be valid JavaScript variable names, otherwise you wouldn’t be able to import them.

Bootstrap uses kebab-case for all its class names, which won’t work. We’ll use a PostCSS plugin called postcss-transform-classes and Lodash’s camelCase function.

One of the names was actually a JavaScript keyword, which isn’t allowed, so I had to work around that. I was also cheeky here and snuck in Autoprefixer, because it’s actually part of the Bootstrap build process.

And that’s it for compiling Bootstrap! Now we just need to put it through ES CSS Modules. It uses PostCSS, so it’s very similar to what we just did.

Step 2: Integrating CSS Modules

We’ve used the file src/index.js as the input. ES CSS Modules will then recursively look at all your files for anything importing Bootstrap . Now we just need some code. For this, I’ll just port over the example over here to React.

The class names are the same as Bootstrap — just in camel case. You’ll probably notice we’re importing bootstrap.m.css — ES CSS Modules understands this, and will just point to bootstrap.css. The .m part is just required for when you bundle your JavaScript. Speaking of…

Step 3: Bundling the JavaScript

Let’s just get this out the way…

And that’s it! We’ve compiled our CSS and JavaScript, and they’ll both be output to the /dist directory. Run it and see for yourself!

It looks slightly different from the version on the website — they’ve added a few lines of custom styling, which I haven’t copied accross.

Optimising

If we have a look at the CSS, we’ll notice that all the classes we aren’t using have been stripped away.

However, we’ll also notice that the class names are huge — this is the default of CSS Modules.

ES CSS Modules allows you to customise how class names are generated via generateScopedName. We’ll use a module called css-class-generator — it’ll give you the next shortest valid CSS class name. We’ll also add cssnano for minification.

Results

The entire Bootstrap from their website minified and gzipped clocks in at 17kb. Our version clocked in at just under 2.7kb. And just for what it’s worth, Bootstrap with all classes removed — the smallest filesize you’ll get with this method — clocked in at 2kb.

The example was not an accurate representation of the amount of Bootstrap you’ll use in a real project, but it does show significant amounts Bootstrap can be removed automatically.

All the code for this is over on Github here.

For more information on ES CSS Modules, you can find the Github here.