I wrote this post for my newsletter, sign up here to get emails in your inbox.


this is a ranty rant, not technical advice. okay? okay.

 

In a component library, should you version and publish each component as a separate package or publish the whole library together?

tl;dr: version the entire library together and publish as one package, for as long as you can


the benefit of versioning each component separately is that every application that uses your component library can pick and choose the components they want to upgrade.

if your library follows semver, patch/minor releases are cheap, new features are additive, so upgrading to new versions doesn’t break anything.

major/breaking releases on the other hand require work!

 

if I work on an application team and only need the new design changes in Button, i’m willing to make the breaking changes required to go from Button v1.2 to Button v2.0. But I don’t want to upgrade all the other components that also might have breaking changes (Form, Dialog, Tooltip, etc.)

this sounds super helpful, each team can upgrade components at their own pace without blocking each other.

the team that maintains the component library can keep releasing new versions (including breaking changes) whenever they need to because application teams always have the option to upgrade or not.

win-win?

not so fast

 

Maintaing this set of components becomes harder when you also have composite components in the library. For example, ConfirmationDialog v1.0 has a dependency on Button v1.2 and Dialog v2.1.

Now, you can’t upgrade Button from v1.2 to v2.0 unless you also have a compatible ConfirmationDialog available

the team maintaining the component library now has a choice:

  • hard option: release a new minor version of ConfirmationDialog v1.1 that works with both Button v1.x and Button v2.0
  • easy option: release a new major version of ConfirmationDialog v2.0 that only works with Button v2.0

The time cost and testing complexity of maintaining multiple versions of a components that are compatible with each other should not be discounted, as it only increases over time with more versions.

Even if the team can afford to take the hard option, the complexity is not contained. By publishing each component in it’s own package, they have transfered the responsibility of compatible dependency management to the application developers (and made it harder with ever-growing permutations!)

package managers might take care of some of these internal dependencies for you. but, depending on how the library is structured, this may not be enough because button probably depends on a ThemeProvider and context that can only used from the same version.

You want to upgrade Button v1.2 to v2.0, easy peasy, as long as you also upgrade ConfirmationDialog v1.0 to v1.1, SelectionMenu v1.4 to v1.5 and oh looks like you haven’t updated Form in a long while, so bring that from v0.4 to v1.2.

dependency management is an even bigger challenge when multiple teams work on the same application because one developer or team might want to use the newer version of a component but not have enough context to make the required breaking changes across the application. this is starting to sound like the point where started.

 

depending on your architecture, you might you might be able to install multiple versions of a component in the same application:

"dependencies": {
   "@library/button": "^1.2.0",
   "@library/buttonv2": "npm:@library/button@^2.0.0"
}

okay, now how do we get ConfirmationDialog to resolve @library/button to @library/buttonv2, will a webpack-alias help?

 

another workaround might be to break your application by functionality or teams where each part has it’s own package.json and javascript bundle. now you can manage your own preset of component verions that are used in this part of the application. (is this microfrontends? 💁‍♀️🦋)

even if you are able to spread this additional complexity around in a manageable way, fast forward a few months and you’re dealing with a peer dependency warnings for minor upgrades, fragmentation of design and increasing bundlesize.

 

I fear that after a certain size/scale, this is unavoidable and the benefits do start outweighing the pain.

I’m definitely not there yet and hope I can push this far into the future.


Want articles like this in your inbox?
React, design systems and side projects. No spam, I promise!