What are monorepos?
- Monorepos are normal git repositories but it gives you the ability to have multiple projects inside one repository so you can use these projects across each other just like any other npm package but still isolate the concerns by putting them in their own directory.
- Just to emphasize IT’s NOT A MONOLITH.
How do you setup the development environment for something like this?
You might be wondering that since each package/project is an independent entity which means they have their own release cycle so how do you setup your development environment because while developing you would need to make changes across packages. Obviously you can’t publish each package for every single change then sit and keep bumping your versions in the
package.json
of the current project to get the latest changes.Let’s imagine what I’m blabbering about. Imagine a repository with the following directory structure
1├── package-12│ ├── src3│ │ ├── mock.js4│ └── package.json5├── package-26│ ├── src7│ │ ├── date.js8│ └── package.json9├── package-310│ ├── src11│ │ ├── api.js12│ └── package.json13├── main-app14│ ├── src15│ │ ├── app.js16│ └── package.json17├── dist (or build)18├── node_modules19├── README.md20├── package.json21├── .eslintrc22├── .prettierrc23├── babel.config.js24└── .gitignore
The structure above describes how typically a monorepo looks like. This gives you the ability to use package-1, package-2, package-3 and main-app as dependencies within each other while developing locally and distribute them individually by publishing them to NPM.
All the packages can also share some configs like eslint, prettier, babel etc. defined at the root.
Each package has its own
package.json
which means they have their own development and release life cycle.
Isn’t it wonderful to see that everything is shared but also isolated at the same time? 🤩
The main question still remains unanswered i.e How do you make it work in real? One possible solution to make them work and what most of us were doing 5 years before was using npm link
but we all know the pain of making it work and then explaining all our team members to set it up. People get frustrated and they literally just give up, then the task goes to a person who actually set it up 🤦♂
Don’t you think that all these things should be handled by a tool? It’s pretty obvious that we are in 2020 and we should have some tools to do this for us and make our life simpler.
NPM, Lerna and Yarn workspaces to the rescue!
These tools helps you setup monorepos, link packages locally and make your development environment buttery smooth.
But with a lot of tools comes a lot of confusion! When to use what? 🤷♂
Lerna, NPM and Yarn
Let me start with the brief description about each of them:
- Lerna: It’s a tool for managing JavaScript projects with multiple packages. It comes with the collection of single-line commands that you can run across packages together instead of going into each package and running them individually. Here are some commands that Lerna provides
lerna publish
,lerna version
,lerna bootstrap
. You can read about the detailed documentation. - NPM and Yarn: They are our best friends and we all know about them I don’t need to describe them 😄
But what the heck is Yarn Workspaces then?
- Yarn Workspaces helps you setup monorepos with multiple packages and manage them.
But wait wasn’t lerna supposed to do what yarn workspaces are doing? Why do we need Yarn workspaces then? 🤔
This is where the real confusion starts. Let’s dive deeper to understand each one of them.
- As I mentioned earlier Lerna helps you manage monorepos with multiple packages with a collection of commands. One of the main tasks when you are working with monorepos is
bootstrap
i.e install all the dependencies of the packages inside your monorepo and link them internally with the help ofsymlink
so you can make changes in one of these packages locally and use those changes in other packages without the need of publishing those changes to registry. Lerna provides a command for this i.elerna bootstrap
. It also provides you with other useful commands likelerna version
similar tonpm version
for bumping your package versions,lerna publish
similar tonpm publish
for publishing your packages and many more. - Yarn Workspaces handles just the bootstrapping part of monorepos i.e install all the dependencies of the packages inside your monorepo and link them internally. It doesn’t gives you any commands or utilities that Lerna gives you to manage your packages within monorepos. When you configure lerna with
"npmClient": "yarn"
yarn’s bootstarpping algorithm kicks in instead of lerna’s. Yarn’s bootstrapping algorithm has proven out to optimise resolution of the packages better over lerna and optimises.lock
files with monorepos.
What about npm
? Can’t we use monorepos with Lerna and npm
?
We can of course use it but there are few things that I would like to highlight about why I prefer yarn
over npm
over here:
1. npm install
fails when you run it from anywhere except the root of the monorepo.
1├── package-12│ ├── src3│ │ ├── mock.js4│ └── package.json5├── package-2 // has package-1 as dependency6│ ├── src7│ │ ├── date.js8│ └── package.json9├── package-3 // has package-1 and package-2 as dependency10│ ├── src11│ │ ├── api.js12│ └── package.json13├── main-app14│ ├── src15│ │ ├── app.js16│ └── package.json17├── dist (or build)18├── node_modules19├── README.md20├── package.json21├── .eslintrc22├── .prettierrc23├── babel.config.js24├── lerna.json25└── .gitignore
- Assume you have the above directory structure and now if you run
npm install
from monorepo root everything will work fine and all your packages would be linked locally. But if you runnpm install
frompackage-2
it’ll fail as it will go and findpackage-1
which is listed as a dependency but it won’t be able to find it on the npm registry as it’s not published. Ideally it should have linked it locally butnpm
is not aware aboutlerna
. This issue also persists when you want to remove some dependencies from within some package for eg: remove some dependencies frompackage-2
usingnpm uninstall
. There’s an open issue here.
2. .lock
files doesn’t plays well when using npm
as the npmClient
in lerna
i.e "npmClient": "yarn"
. It’ll generate package-lock.json
per package and this makes it difficult to run any npm commands like install/uninstall from within the packages directory itself.
Benefits of using Yarn workspaces.
While using monorepos with yarn workspaces you get some benefits out of the box:
- Yarn mainatains just one
yarn.lock
at the monorepo root whenworkspaces
are enabled. - You can run
yarn install
/yarn remove
either from monorepo root or from within any of the packages directory. Since it maintains just oneyarn.lock
file at the root running these commands also updates theyarn.lock
. - It helps to hoist
node_modules
by default at the monorepo root. Although this can screw up things sometimes(especially with react-native projects) but it’s fine for most of the case. You can also disable hoisting if you wish to. - All the benefits of
yarn
also applies for example caching. This boosts the packages installing time drastically especially when your monorepo is growing and you don’t want to wait for a long time when you runyarn install
.
FAQs
1. How do I setup yarn workspaces
?
- To enable
yarn workspaces
you just need to addprivate
andworkspaces
keys to yourpackage.json
1"private": true,2 "workspaces": [3 "package-1",4 "package-2",5 "package-3",6 "main-app"7 ],
2. How do I setup lerna
with yarn workspaces
?
- add
workspaces
to yourpackage.json
as mentioned in point #1 above. - install lerna at the repository root.
1yarn workspace -W add lerna
- create
lerna.json
at the repository root.
1{2 "version": "1.0.28",3 "npmClient": "yarn",4 "useWorkspaces": true5}
3. Do I always need lerna
when working with yarn workspaces
?
- No. Lerna just provides you with set of commands that helps you manage the release, build, publish tasks of multiple projects with simple single-line commands. So you can use yarn workspaces independently if you don’t want any of the above mentioned tasks or if you already have your own scripts to do that.
4. Is there any alternative to lerna
?
- Yes. Changesets created by folks at Atlassian.
I’ve created this this repository to demonstrate the setup of monorepos with lerna
and yarn workspaces
.
If you have ideas or thoughts around monorepos or want to share your experiences with monorepos(Good/Bad) then you can write it to me or you can DM me on Twitter. I would love to hear them!
P.S. If you like this, make sure to subscribe, share this with your friends and follow me on twitter 😀