My name is Vittorio and I am working as full-stack engineer in Nuritas, an AI/Biotech company.
During the last few years, I have worked on several projects (small and big) where I had to learn few things, remembering others and combining different domains.
Almost always these projects required a UI and given my familiarity with React I focused on bootstrapping small POCs/MVPs that had less dependencies as possible (sometimes it was actually a requirement to not rely on any of the big players like Ant, Bootstrap, Material-UI).
While working on these projects I setup a base that allowed me to share previous knowledge and custom additions. With slow pace I finally put it together in a presentable way, releasing it as a repository to copy or as npm package.
The goal of this project is to create and maintain a UI component library base for creating POCs/MVPs or new projects (i.e. dashboards), with the following requirements:
- being extendable in an easy way: adding a new component should be an easy and repeatable operation;
- consistency: the overall experience (both for the user and the developer) should be consistent between components and packages;
- well documented: the components should be clear and simple, and they need to have a good documentation and examples;
- being tested: when your components are supposed to be the core of something (a dashboard, a website) you just don't have time to test each single scenario manually on every change;
- should have less dependencies as possible, but still be as much complete as possible without reinventing the wheel (for example, the excellent
- work as self-documentation for configuring the most common scenarios (i.e. bundler, integration with CRA, etc);
- being open source: sharing and contributing is the key of being part of a community, and giving something after all the taking is a great feeling!
- being a playground to learn new things: before starting it, I had no idea of the complexity of creating and maintaining a component library, or how to create an npm package, a monorepo with Storybook, etc.
The component library can be either integrated in an existing project or as a monorepo starter. The project website has a getting started section that can guide in both ways. If you are really brave, there is also an npm package with all the components of the library ready to be used.
Few keywords first:
borrow-ui started a couple of years ago as a personal project, and given the different requirements the first idea was to organize the library and the actual app/website in different folders. Monorepos are the best solution I could found and initially borrow-ui integrated
lerna. Unfortunately, the
lerna project seems to be unmaintained and the issues arose when working with
yarn and some deep interdependencies. For this reason,
yarn 3 with workspaces have been chosen: it's more verbose but it does the job.
The library itself has a small number of components which are tested by the amazing
react-testing-library ("how easy to use is it?!" <- rhetorical question). The coverage of the core components as of today is ~97%. The test suite is run when a pull request is created, using the Travis-CI open source program.
The library is styled with SCSS, following BEM convention.
Each component also has a Story file written in
.mdx, and shown using the
docs plugin in the
documentation package (a Storybook installation already configured to source the components).
The component library is bundled with
rollup, which was the lightest choice at the time but still complete for all my use cases.
The monorepo contains the main package with all the components, called
ui, and other three small packages:
documentation: a configured Storybook which allows to develop new components very easily, and also produces a good technical reference;
dashboard: a small example of an application created with create-react-app (CRA), which I use as a base and demo for dashboards before starting new projects. It has two apps, one created to show how to use the components of the library and the other one as a "scalability" example. The code is extensively commented; as a side note, I use this dummy project to show how to organize components and files in a React project;
website-next: an example of how to integrate the library in a Next.js app, how to configure it to use
mdxand how to add additional custom components (all this is explained as blog posts in the demo itself).
Creating and maintaining a component library can be really difficult and tiring.
The common scenario (of any library) is when you add something and that slightly changes - or breaks! - something else, but this can be mitigated with a good test suite. Or similarly when you need to change the APIs of a component, and you have to update the dependent applications: reducing this changes is a must for a library.
Choosing other libraries and components to integrate is one nice part of it, while the less-nice part is how to make them look consistent with other components. Two examples are
react-day-picker which have excellent APIs but their style does not match with the library one (few times I was tempted to change again and again the UI library instead of adapting the components, but that desperation went away in the end).
The biggest challenge has been maintain the library up-to-date and consistent. If you need to use different components in the same page, they should look (relatively) well together, otherwise the eye is not satisfied and the functionality compromised.
Where to go from here?
The two next steps will be creating a dark mode (and possibly treating it as a theme rather then just a binary option) and the conversion to Typescript (or maybe a separated branch?).
Both things are new to me and it will take some time and research before, so any suggestion is welcome (double appreciated if in the issues section of the repository)!
A better roadmap is available on the website, or in the milestones section of the GitHub repository.
I really hope this project and my trial and errors can be useful to anyone that will have to start a similar journey, even to borrow some configurations or a single component.
It has been hard & funny to work on this project, and I am excited to moving it forward to make it more useful.
Thank you for reading all this long post!