Using Lerna with NX to automate versioning

Note Statistics

Note Statistics

  • Viewed 994 times
Tue, 09/28/2021 - 20:54

Lerna and NX are two great options for monorepos. However, they have different use cases. While Lerna is focused on linking package from the same project, NX is focuses in managing development workflow for mutiple packages.

Lerna

The Good: Is a better fit for open source project with muntiple packages since you can easily publish related packages while keeping their versions synchronized.

What is missing: No tooling for package boilerplate. I you use Typescript for example, you handle boilerplate and build process yourself.

NX

The Good: Is best for development workflows. Multiple plugins and boilerplate are avialble for various frameworks, React, Angular, VueJS, NestJS, Express etc. Out of the box commands for

  • Generating new project (using plugins of course) for your target framework (NestJs, Angular, React etc)
  • Building projects
  • Testing projects

Whats is not so good?

  • Single package.json file for all the projects. Meaning that all the project (or packages) have to use the same version of the same package.
  • While using the same package.json has some advantages it also has challenges. Front-end App benefit from tree shaking process that removes unused modules. However, Back-End Apps will be bundled with unused packages causing a bloat in App artifacts (with Docker for example).

Why not use both?

Since none of them is perfect why not use both and let them complete each other's weaknesses. We get the best of both worlds. Follow the steps below to use them together.

1. Create an NX Workspace

npx create-nx-workspace

2. Install Lerna

npm install lerna --save-dev

3. Create a lerna.json file

{
  "packages": [
    "libs/*"
  ],
  "version": "independent",
  "command": {
    "publish": {
      "conventionalCommits": true,
      "yes": true
    },
    "version": {
      "message": "chore(release): publish"
    }
  }
}

4. Conventional commits

When using conventiinal commits you can

  • reinforce a convention for commit messages using conventional commits
  • automatically update package versions (patch,minor, major) based on commit messages.
  • automatically generate changelogs

4.1 Install commitizen This package helps us to commit the message in the conventional-commit format

npm install commitizen -g

4.2 Initialize project

Initialize your project to use the cz-conventional-changelog adapter

commitizen init cz-conventional-changelog --save-dev

or with yarn

commitizen init cz-conventional-changelog --yarn --dev

The above command will

  1. Installs the cz-conventional-changelog adapter npm module
  2. Save it to package.json’s dependencies or devDependencies
  3. Adds the config.commitizen key to the root of your package.json as shown here:
...
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }
	...

You can now run git cz to commit messages.

5. Set publishConfig

Most if not all NX project are TypeScript project that are build. Lerna is not aware of this. For each package update the package.json to point to the build directory. If your package is named mypakage, you should update the package.json as below

"publishConfig": {
    "access": "public",
    "directory": "../../dist/libs/mypackage"
  }

6. Build package with NX after version updates by lerna

When you are ready to publish you pakage you run `lerna publish`. This command does 2 things
1. There is a version bump by leran using `npm version`. This update the package.json version (and package-lock.json) if there is.
2. The changed packages are published.

Before publishing the package we need to make sure that the built source code has the most up to date changes including

  • The source built code
  • The updated version of the package.json file (and package-lock.json)

To do this we add a script to the package.json

"version": "npm run affected:build"

This script makes sure that after updates the package.json file, both the built source code and package.json (+ package-lock.json) are updated in the dist folder before publishing.

Voila!

Now you get the best of both worlds. You can use NX for development workflow and Lerna for synchronising package version and publishing the related packages.

Authored by