Ledger Live Monorepo Project: Part 2 – The Tools (Make it Shine)
Second entry of the blog posts series “Ledger Live Monorepo Project”, where a Ledger developer tells us the story of the Ledger Live codebase huge migration into a mono repository. If you missed part 1, check it out here:
After establishing that a monorepo architecture was a viable solution, we then started to look into the available tools to put in place our plan.
Handling multiple projects
In the Ledger Live team we navigate in the JavaScript ecosystem, and fortunately for us, we already knew of several ways to handle multiple projects with our package manager. Some of those possible solutions include:
- NPM (has support for workspaces but better alternatives),
- Yarn 1 (becoming too old, better and more efficient alternatives),
- Yarn ≥ 2 (interesting idea, but plug n play not well supported everywhere, especially with React Native),
- PNPM (symlinks, built with workspaces in mind, disk efficient).
After looking at all these, we decided to go with PNPM for:
- the disk efficiency (it uses a virtual store and symlinks, so packages are downloaded only once then symlinked to your node_modules from the virtual store),
- the speed (since packages are cached, subsequent installations are much faster),
- built in support for workspaces/monorepo architecture (aliases, orchestration etc…).
On paper PNPM is an absolute gem, but symlinks were a bit odd to setup correctly (again, specially with React Native).
Ok, so our choice was made, we would go with PNPM.
Script Orchestration
Even though PNPM adds more and more orchestration to its features, it still doesn’t cover everything we wanted to do, such as:
- sequential builds,
- caching.
For these, we found two interesting contenders that we needed to take a look at:
- NX (by the angular team),
- Turborepo (which just announced the v1.0.0 when we started working on it, and now working with the Vercel team).
We did a proof of concept on both.
NX had much more features, generators, automation, great dependency graphs etc… but, it added a lot of overhead, and since it’s pretty opinionated, we would have to follow their conventions.
Turborepo on the other hand, is pretty basic feature wise. Yet it’s a convenient plug and play solution that we could change very quickly if the need ever comes.
Even though Turborepo had less features than NX, it did the 2 things we were looking for:
- Orchestration of builds respecting the dependency tree (and concurrent builds),
- Caching (builds are cached and ‘replayed’ if their code has not changed).
That, plus the easy drop in / drop out, made us choose the new kid on the block, TurboRepo.
Versioning
We looked into several solutions as well, but ultimately decided to use https://github.com/changesets/changesets as it was one tool TurboRepo recommended, and after a bit of documentation reading, seemed to comply with our needs.
Developers would need to be a bit more rigorous in their dev flow and provide changesets
(file describing which library their code changes, the severity following the semver convention, and a description of the change). These changesets
are then used to automatically bump the version of the packages respecting the given severities, as well as automate the generation of changelogs. On top of that, the tools allows for pre release
mode, the 🍒 on the 🍰.
What’s next ?
After deciding on the tools, it was time to start working. In the next blog article, we will talk about the build system and all the dev-ops / automation / continuous integration in the context of a mono repository.
Valentin DE ALMEIDA
Developer Experience & Core Tech – Ledger Live