Things I have learned while maintaining JavaScript monorepo with Lerna
source link: https://vladimirgorej.com/blog/things-i-have-learned-maintaining-javascript-monorepo-with-lerna/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Things I have learned while maintaining JavaScript monorepo with Lerna
Written on 07 September 2021This is a second part of the article series dealing with monorepo management using Lerna. First part was dealing with monorepo management in depth using Lerna and npm local paths long before npm@7 workspaces were introduced. This article will try to describe monorepo management practices in the world of npm@7 workspaces. Nevertheless, I highly recommend you to read first part of this series to be familiar with how things used to be.
What is monorepo ?
Let’s first define what monorepo is:
Monorepo is a software development strategy where code for many projects is stored in the same repository.
Monorepo code is usually divided into separate contexts, called packages. Every package contains code specific to it’s context and can depend on zero or more other packages within monorepo. Monorepo must have a mechanism how to interconnect packages and allow us to use one package code within another.
In further texts I’m assuming you have your monorepo setup as described in first part of this series.
Dependency management
Dependency managed has been simplified significantly with npm workspaces. npm workspaces require npm@7.
This version of npm is using new format of package-lock.json
file.
You’ll need to convert your package-lock.json
file to new format in order for workspaces to work correctly.
A word on expressing dependencies between packages
We now use asterisk symbol to express dependencies between different monorepo packages.
Given that following are dependencies of package-c
which requires package-a
and package-b
,
this is how we express it in package.json
:
"dependencies": {
"ramda": "=0.27.0",
"ramda-adjunct": "=2.27.0",
"package-a": "*",
"package-b": "*"
}
Notice that we no longer use explicit npm local paths but rather an asterisk symbol.
asterisk symbol is translated to npm local paths under the hood in package-lock.json
file.
Before npm workspaces, we had to list all packages in dependencies
field of main monorepo package.json
file.
"dependencies": {
"package-a": "file:packages/package-a",
"package-b": "file:packages/package-b",
"package-c": "file:packages/package-c"
}
This is no longer required. npm workspaces support recognizing monorepo packages by defining
a workspaces
field in main monorepo package.json
file:
"workspaces": [
"./packages/*"
]
Whenever we add a new package now, we don’t need to add it explicitly as a dependency. This saves time and prevents cryptic errors when we forgot to add the package explicitly as a dependency.
A word on development dependencies
It is no longer required to keep all development dependencies in main monorepo package.json
file.
Every monorepo package can now have its own development dependencies in particular version given
the particular needs of a particular package.
Before npm workspaces, devDependencies
field of every package package.json
file was ignored.
Now npm@7 recognizes it and installs the npm packages listed in devDependencies
.
IMHO it still makes sense to keep certain devDepedendies
(like testing frameworks) in main
monorepo package.json
file.
A word on topology
npm workspaces are aware of monorepo package topology. Workspaces know that
package-c
uses package-a
and package-b
as its dependencies. Let’s run following command which run build npm script
in all the monorepo packages:
$ npm run build --workspaces
This command will run npm run build
for all the monorepo packages. But it seems that npm workspaces
don’t run the command for monorepo packages in an order as we’d expect. Let’s say that package-a
depends on package-b
and package-c
depends both on package-a
and package-b
. The order of execution you get from running the command is:
- package-a
- package-b
- package-c
But the correct order of build should be:
- package-b
- package-a
- package-c
Because of this Lerna still plays major role here. Lerna will find out which packages have build npm script defined and then it determines the proper order of execution.
$ lerna run build
Order of execution:
- package-b
- package-a
- package-c
A word on installing a new dependency
npm workspaces completely simplified process of adding a new production dependency. Let’s say
we have a package-a
and we want to add a dependency of [email protected]
. The only thing
we need to do is run the following command:
$ npm install [email protected] --workspace=package-a --save
A word on installing a new development dependency
As already stipulated, development dependencies can be installed either in top level monorepo (suitable for testing frameworks)
$ npm install mocha --save-dev
Or installed as a specific development dependency of a particular monorepo package
$ npm install rimraf --workspace=package-a --save-dev
A word on npm binaries
Before npm workspaces, in order to run a binary from one of the monorepo packages, we had to use link-parent-bin npm package to link top level npm binaries to all monorepo packages. This is no longer required as npm supports this natively.
Closing words
Given all that has been written here, I think npm workspaces still doesn’t replace Lerna, rather they just significantly simplified how we work with Lerna. Lerna still plays a major part in change detection, releases and running npm scripts in proper order (given the package topology).
All the examples mentioned in the article can be found in following Lerna monorepo repository I’ve setup-ed for you. Clone it, install it, play with it and have a lot of fun with it!
Maintaining Lerna monorepo series:
- Part 1: Things I wish I had known when I started JavaScript monorepo with Lerna
- Part 2: Things I have learned while maintaining JavaScript monorepo with Lerna
Recommend
-
91
Monerepo with lerna At Kudobuzz we have lots of services in N odes,js , this naturally comes with writing many reusable packages. No...
-
7
In this post, I will walk you through how to use Lerna to manage, and publish, two packages under the same monorepo. Publishing will be done to my private GitHub repository under the GitHub packages registry. I decided to keep it as s...
-
6
How to Use Lerna to Create a Monorepo for Multiple Node PackagesCreate two packages, hello-world, and aloha-world (with the default options):0 reactionslerna create hello-world lerna create aloha-worl...
-
7
上古时期,前端没有工程化的概念可言,复用代码也不过是将某些 css、js 代码片段保存到笔记,需要时复制到项目中,仅此而已。参考:55 个提高你 CSS 开发效率的必备片段,或是
-
15
Prerequisites Some Javascript and Git knowledge and a Github account. Also,
-
12
Repository with full code if you want to follow like thathttps://github.com/KevBeltrao/microfrontend-monorepo-article What do I expect from you
-
4
Monorepo Javascript Projects with Yarn Workspaces and Lerna Monorepo is a software development strategy in which a single repository contains code for multiple projects with shared dependencies. It has a...
-
4
Between 2016 and 2018 I maintained an open-source project with +800k downloads/month. I learned six invaluable lessons by doing this, and I will now share them with you. How It All Started 🛫 ...
-
4
@prplcodeSimon Egersand 🎈Sr. Software Engineer @Spotify | Tech Blogger 💻 | Professional Nerd 🤓 | Musician 🎸
-
5
在开发中,我们可能会遇到多个项目有相同或高度相似的业务场景页面,这里我们可能会进行复制粘贴已有的组件,但是,这种解决方案并不值得提倡,那么本文我们探索一种比较优雅的解决方案。最近有个项目,有着多个代码库,其中有插件、业务组件等相互依赖,...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK