7

Things I have learned while maintaining JavaScript monorepo with Lerna

 3 years ago
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.
neoserver,ios ssh client
Things I have learned while maintaining JavaScript monorepo with Lerna

Things I have learned while maintaining JavaScript monorepo with Lerna

Written on 07 September 2021

This 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:


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK