10 Lessons Learned from 4 Weeks of Updating Bootstrap

Another developer and I have spent about 345 hours updating the Bootstrap and React Bootstrap versions on two web apps, plus more hours responding to feedback from the client team members manually reviewing the changes. That’s roughly four weeks of two developers working exclusively on this update.

This update was going to be a pretty big effort no matter what. This Bootstrap update — from version 3 to the current version 5 — was really big. It saw: the use of Flexbox by default, an overhaul of the Grid system, multiple new media breakpoints introduced, and completely different responsive display utility class names.

But, many things could have made this update much faster and much less frustrating.

Use types.

These two React projects were written in JavaScript. Many of the changes to the react-bootstrap API could have been detected while trying to build the project, rather than running the project and seeing the page crash (or seeing things just quietly look funny). The editor support you get with TypeScript would have saved us time spent combing through migration guides to identify straightforward changes to these components.

Write tests.

These projects also did not have comprehensive test suites. One of these projects had a small handful of Cypress tests, and I was overjoyed when a failing test alerted us to a new issue we introduced. Unfortunately, since the test suite was so small, there are probably quite a few more new errors we have yet to uncover. I often skip writing thorough component tests or E2E tests for super simple interactions. However, these tests do uncover problems with your use of your dependency’s changing APIs, just as they do with your complicated code.

Use tools for detecting visual regressions.

At one time, these projects did use Storybook and Chromatic. However, the tools were removed because Storybook can be difficult to maintain. Also, it seemed nobody was actually using them to invest in maintaining existing stories or creating new ones. In the past, I always complained about Storybook for this reason, and would have never chosen to pull it into a new project. But this experience has made me reconsider. Being able to test components in isolation and better detect visual regressions would have really increased my confidence in the update.

Be able to run the project as if offline.

A good amount of the time we spent updating these projects was simply sitting there waiting for requests to super slow APIs to finish loading. This is another reason its great to have Storybook to help you iterate on components running in isolation. Or, on previous projects, I have depended heavily on running the project in test mode (where it is hitting a locally running test DB and mocked out APIs). If there had been good investment in setting up the infrastructure for system testing, we could have had another big win for free — skipping slow requests to outside services, while still getting to step through full user flows.

Avoid using CSS selectors defined by the framework.

There were many places throughout these projects where Bootstrap class names applied by React Bootstrap were used to access elements for additional style customization. This can be super tempting when the component is close to the expected design but not exactly right and when the component doesn’t provide a way to access a deeply nested element. But, the class names defined by Bootstrap can and will change. When they do, resolving such an issue will require a lot of squinting at DOM elements and a lot of searching through previous and current documentation for differences.

Use shared components.

Say you have no choice but to use a CSS selector defined by the framework. Consider tucking that away into a single reusable component instead of spreading references to a class name that’s likely to change throughout your code base. And even if you aren’t using custom selectors, it can still be good to have a, say, AppButton, so that any customization is applied consistently, and so you don’t have to sweep through the entire code base if and when the component library’s API changes.

But don’t let them be infinitely customizable.

However, be careful with how customizable you allow shared components to be. It’s fine to say that a reusable component can be configured in predictable ways, such as an alert being red, yellow, or green. But completely free access to customize a shared component defeats the point. In a few places, a class name applied in a shared child component was then referenced in a nested selector used by a parent component’s CSS. It was surprisingly tricky to track down relationships like that. Similarly difficult to track down were styles passed down through completely generic style props, so use those sparingly.

Make the most of global customization options.

Bootstrap makes loads of variables and mixins available for customizing the look and feel of elements – way more than I would have expected. Use them. It can be tricky at the beginning to know whether something is a global style option or not. And it may not be obvious just how many things your tools allow you to customize. So, pay attention to when styles start to be applied to similar elements consistently. Check whether there is a way to make that customization globally and consider stopping to make the change.

Follow the guidelines recommended by your tools.

Bootstrap encourages responsive styling with CSS over JavaScript. So, places where the code tried to detect screen sizes and conditionally render things in the JS caused unexpected and confusing conflicts. Try to follow the recommendations that the framework offers.

Don’t customize default components.

Many pain points we encountered came down to the customization of things that really didn’t want to be customized. So, this experience has encouraged me to consider pushing back against, or outright abandoning, designs we cannot implement easily with the components and theming options available in the library. The chances are usually good that elements don’t have to look exactly 100% as designed, as long as they serve the same purpose and fit the general look and feel. Settling for good enough can save a lot of future pain.

I believe some of these practices could have simplified this update, and I will try to prioritize them more on future projects.


Join the conversation

Your email address will not be published. Required fields are marked *