Before diving into Lerna, Bit and other monorepo tools, think what you’re building, who you’re building it for and why.
The overhead around managing multiple packages in multiple repositories has been leading many teams to explore the old-new concept of a monorepo.
Today, this doesn’t mean a huge spaghetti codebase but rather having a repository where multiple packages are hosted in and published from.
This repository can be an application, a shared library or any other structure containing multiple packages published from the same repository. Some find this also makes it easier to manage commits, run CI/CD and manage changes.
As the concept grew, so did the ecosystem and tools to support it.
In this post, I’ll try and help you determine which setup and tooling might work best for your “monorepo”, depending on what you wish to achieve. For this purpose, I’ve gathered 5 questions which affect these choices.
I hope this can help you save time and make the right choice for your needs. Please feel free to comment, add your own insights and ask anything. Enjoy.
1. What are you building? (Library? App?)
Before moving ahead, you should stop and ask yourself “what am I going to do with this project?” In many cases, the answer would be “I’m building an application” or “I’m building a library for the teams building applications”.
Each of these answers means different things for the setup of your monorepo. If it’s a library, it will probably contain a relatively large number of individually useful components which can be used on their own. In this case, Bit can come in super handy for publishing the components at 0 overhead.
If it’s an application (or a standalone project), it could contain components and modules and also some larger core modules. If you wish to separate and publish a relatively small number of larger packages, Lerna can come in handy for automating the management and publishing of the packages in the repo.
For example, here is the React Foundation component library. Using Bit, all of its components were made available to individually discover and install. This didn’t require any refactoring, and the goal was achieved in a very short time.
React-foundation components with Bit
Here is another example, this time for handling a few core packages with Lerna. Vue-CLI is using Lerna to handle core packages while each can be individually published to NPM. We’ll dive deeper in the next questions.
Vue-CLI core packages with Lerna
2. How many packages?
This question is essential to understand the scope of the project, and directly affects your choices. If you have 30 smaller components or 10 larger packages (or both), your cost-benefit might change for your choice of setup.
Bit requires 0 work and 0 refactoring for sharing components from a repository, making them available as packages with NPM and Yarn. It provides additional values for discoverability and collaboration.
This means that if you wish to share a large number of packages from the repository, Bit will 1) Save you the refactoring overhead which grows with every package 2) Automatically manage all dependencies for the components and the relationships between them including updates and changes 3) Provide discoverability and organize the packages visually.
If you have a few core packages and intend to create and configure their setup and environment manually anyway, Lerna will help automate these processes to save you time compared to doing it yourself without Lerna. Here’s a basic Lerna structure:
my-lerna-repo/
package.json
packages/
package-1/
package.json
package-2/
package.json
Lerna automates tasks for packages in the monorepo. Thelerna run build will run npm run build inside each sub-package and lerna publishwill publish all packages to npm and will update git tags, etc. Then, packages can be installed from NPM’s registry.
You can also combine both. Use Bit as 0 cost (work) to share all the components, and add Lerna for the core packages you’re diving into anyway. Both can also be combined with Yarn workspaces to optimize the installation of external packages in the repository.
3. Who’s going to use these package?
Here’s another key question: Who’s going to use the packages you share from your repository? The answer can be you, your team, multiple teams or the OSS community. Each answer can affect your choices differently.
If more people other then yourself are going to use these packages, you should be minded to providing people with a quick way to find them and learn how they work. Preferably, without writing and reading long docs sites.
Bit provides this out of the box through its component hub. Component collections include a visual preview of the examples you save. Component pages include a live playground with hot reloading. Each component that has test files will be tested in the cloud and the results will be shown. Docs from the code will be automatically parsed and presented near the playground.
Each component can then be installed with Yarn and NPM from Bit’s registry, using your native NPM client just like any other NPM package.
Rect Pacman component in Bit’s playground
If using Lerna, packages will be published directly to the NPM registry. When publishing packages for other people, it’s recommended to also set up and maintain docs sites and wikis so that people can find packages and learn how to use them. Useful tools can be docz, Storybook, Code sandbox etc.
4. How will you manage changes and PRs? (and dependencies in the repo…)
This question is particularly relevant to use cases when you are trying to create adoption for your library. It can be harder than you think.
Many companies mistake to think that they can force developers to adopt a shared library. This might work in the short term (not really), but is bound to fail over time. You can’t get adoption for the library if people don’t want it.
So, you have to ask yourself: why don’t they want it?
After listening to many UI architects recently, I came to realize that the main blocker for adoption is that people don’t want to put in their code something they dependant upon but can’t develop.
For your “consumer” (which can be the developer in the table next to you), it will take a long time to dive into your monorepo and make changes. Even then, who’s to say if you will approve them- and when? So, they won’t use it.
To create adoption for the library’s packages you need to make it easy to PR changes in a short time cycle with a short learning curve. Otherwise, people will be required to spend a whole day to change a component when it could have taken them an hour. Then, they’ll also have to wait for your OK.
So what can you do instead of chasing people around?
If you use Bit, you will probably make this process easier for other people:
a) As your library’s structure didn’t change, it’s easier to dive into and issue PRs right into the monorepo. Since Bit automatically updates and manages dependencies, when a single component is changed all the components depending on it will automatically update as well. This means that other people can more easily get in the code and suggest changes to components.
Bit updates components automatically when a change was made to their dependency
b) They can choose to make a PR to the repo itself, or, use Bit’s “distributed code-sharing” workflow. Meaning, every component can also be imported right into any other project, changed there, and updated with a version bump or as a new component. This means that another developer who wants to use the component doesn’t have to wait until you approve the PR.
Is using Lerna, PRs will be made directly to the monorepo. When a change was made, the contributor will have to manually maintain all relevant files and dependencies in the repository. This process might be a bit more complex than making a PR to a “normal” repo or library but is not impossible, and I've heard of teams who got this process going one step at a time.
Both Lerna and Bit can be added to the CI/CD release management cycle of the project, which is quite convenient and useful in both cases.
5. Are you working on an Open-Source project?
Here’s one last point to think about: are you going to release this project as open source? all of it or just a part of it?
Lerna works just as well in both cases. You can setup an open source library for example, and publish its packages to NPM. You can do the same for a private repo with a private registry. The only limitation is that changes to the packages will have to go through the repo, open source or private, which affects the consumer’s ability to PR changes. Lerna also has an abundance of tutorials and resources around the web, which can help to some degree.
Bit can be used in either case as well. It also opens up a 3rd possibility, which is to only share some of the packages as open source. With the bit import workflow, people can make changes to these packages alone, right from their own projects. So, it’s a fast way to make some parts of the repo OSS.
Conclusion
Going “monorepo” today usually means turning a repository into a multi-package repository from which multiple packages can be published. This repository is part of a multi-repo architecture and lives in its ecosystem.
Tools like Bit (which was built for code-sharing in a multi-repo codebase), Lerna and Yarn workspaces help to optimize this workflow, and breed code-sharing for faster development and simplified maintenance.
Choosing the right tooling means understanding what are you going to build, why are you building it, and how do you expect other people to use it. Answering these questions can help you make good choices from the get-go, which will make your life much easier down the road.
Don’t forget: sharing code is about tools and technology, but also about people and communication. The right tools can help you share and communicate, but won’t replace team-works and collaboration.
Thanks for reading and please feel free to share your own insights and experience with others! Cheers.
Top comments (1)
I did this for a job interview project, I got criticism for over engineering which was a shame because TDD was much easier in this layout of repository. Each component was its own package, perhaps I took it too far 😅