How I use Lerna with Nx to automate the versioning
In this article, we will see how we can automate the versioning process in nx repos(monorepos) with the help of the Lerna, Conventional Commits and commitzen. Although the Nx provides all the important feature that makes it different from Lerna, one thing that we can use from Lerna is to automate the package versioning. This would be helpful in CI/CD.
Let’s get started with creating the Nx workspace:-
npx create-nx-workspace@latest flair
This will create a new Nx workspace with a name flair. You can use any name you want.
Now let’s install the other required packages:-
npm install lerna --save-dev
You need to create a lerna.json file in order to use Lerna in Nx repo. Simply create a lerna.json file in the root with the following options:-
The first configuration in the lerna.json file tells Lerna the path of the packages/libraries. The Nx workspace has libs folders for the libraries.
The version property inside the lerna.json will tell the Lerna to bump up each package individually(in case of multiple repos).
How Lerna detects it’s a patch or minor or major bump in the version?
We know that npm uses semantic versioning to control the package versions. Lerna has a couple of useful commands. One of them is
lerna version
We can combine this with Conventional Commits. You can learn more about this in their docs. By using this commit message convention, we can define the type of the commit. For example, Is it a bugfix, feature, refactoring, breaking change, etc. This would help us to decide to bump up the patch or minor or major version. If it’s a bugfix, Lerna will bump patch version. If it’s feature then, minor version and if it’s breaking change then it’s the major version.
If you look into the lerna.json file, we have the conventionalCommits set to true inside the publish command. This will tell Lerna to follow the conventions of Conventional Commits and bump the version accordingly.
The next package we will use is commitizen. This package helps us to commit the message in the conventional-commit format:-
npm install commitizen -g
Initialize your project to use the cz-conventional-changelog adapter by typing:
commitizen init cz-conventional-changelog --save-dev --save-exact
Or if you are using Yarn:
commitizen init cz-conventional-changelog --yarn --dev --exact
The above command does three things for you:-
- Installs the cz-conventional-changelog adapter npm module
- Saves it to package.json’s dependencies or devDependencies
- Adds the
config.commitizen
key to the root of your package.json as shown here:
...
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
Now whenever you run below command in order to commit message:-
git cz
you will be prompted with the following form:-
There is one issue of using Lerna with the angular specific project. Lerna doesn’t provide good support for the typescript specific project. Since the angular uses typescript, so when we build the angular libraries, those libraries goes inside the dist folder inside the root folder. Lerna doesn’t know anything about the dist folder.
The solution to this issue is we can define this config inside the package.json file that is specific to the library. So inside the package.json of the library, we can define the below config:-
"publishConfig": {
"access": "public",
"directory": "../../dist/libs/core"
},
Here we are defining that when we are going to publish the package, go inside the dist folder and publish the core library which is inside the libs folder. If we have more than one library, we need to define this config for the other libraries.
Since we know that Lerna doesn’t have the good support for the angular projects, we need to do some customizations in the root folder’s package.json order to automate the versioning process.
First add the below script:-
"postversion": "npm run affected:build"
We know that npm has pre/post hooks that will be triggered when we run the scripts(for example, npm run publish, npm run version, etc).
This script will be run after the version bumps up. We will discuss later why we need this and how this will work together with Lerna.
Next, add the one more script:-
"publish:libs": "lerna publish"
This is the script that we need to run whenever we want to bump up the packages.
When we run this script, Lerna internally first runs the lerna version command which will automatically bump up the package versions based on the commit message.
We have postversion script which will be run after the version bumps up. The reason behind using this hook is we need to build our libraries with the updated version, not with the old version. Otherwise, when we are going to publish the library we will get the error, the library is already published. So that’s why we need this hook in order to build our libraries with the new version.
After we have built the library with the new version, Lerna will publish them to the registry(public/private). We can include this inside our CI/CD process.
Below is an example of how it works:-
Feel free to clone and play around it.
That’s it.