Log In

Lerna Introduction


by Yariv Katz

An important lesson I learned during my 20 years experiance of building frontend apps and managing frontend software team, is the importance of monorepository. In this lesson we will learn about Lerna and how to create monorepository for our frontend projects.

What is monorepository?

Under a single SVN we arrange all our projects and libraries, that is monorepository. On the plus size it makes it easier to be exposed to all of our code, thus making code reuse more approachable to every team memeber. On the downside it does make deployment of each single project, a bit harder. Still monorepository is a must for every organization.

How can we arrange our frontend projects in a monorepository?

We can use Lerna a tool for managing multi package projects to divide our frontend to different packages. Let's start by initiating Lerna.

> mkdir lerna-tutorial
> cd lerna-tutorial
> npx lerna init

The result of this command is the following:

  • packages folder - our different apps and libraries will be arranged in folders there
  • lerna.json - specify configuration data about lerna and your mono repo
  • package.json - manage dev dependencies and scripts for the entire repo

Fixed/Locked mode VS Independent mode

We need to decide how Lerna will manage our packages. In Fixed mode we have a single version and when packages are updated they will all be published under the same version. It will be the way to use if all the packages are tied together. In my case I had different projects that are not tied together where each one needed a separate version to maintain. So we need to switch to Independent mode where each package will have it's own version. To change the mode modify lerna.json to the following:

{
  "lerna": "3.15.0",
  "packages": [
    "packages/*"
  ],
  "version": "independent"
}

Create your first package

to create our package we will make sure our lerna is updated to the latest and then use the lerna create command

> npm install lerna@latest --save
> lerna create @nz/hello

Notice that the packages we want to remain private we will prefix with a scope. In nerdeez our prefix is @nz but it very much depends on a decision in the organization. Let's add some logic to our package entry point, in the folder: packages/hello/lib/hello.js modify the code to this:

module.exports = hello;

function hello() {
    console.log('hello world')
}

Publishing our package

Now that we have our package it's time to publish the package to npm. If your package is scoped like we did with the scope @nz to reserve a scope in NPM you can no longer use the npm free account and you will have to pay for a private npm account. Another option is to create your own company private npm registry using one of the open source packages like: Verdaccio Every publish you make you will first have to commit your changes. after that to release your package simply run the following command:

> lerna publish

It will ask you a question regarding the version of this update. A version is made from 3 numbers:

  • The right number is called patch and signifies bug fixes in your package.
  • The middle number is called minor signifies new features in your package bug the general API did not change.
  • The left number is called major and signifies a new version and a new updated API that might require modification in your end if you are using this package.

For the question about which version is the update you can choose to update the patch. Now every time you want to update your package simply commit your changes and run lerna publish again.

Package that depends on another package

How do we maintain package dependencies with Lerna, what if a package in our workspace depends on another package in our workspace. Let's try to deal with this scenario by creating another package:

> lerna create @nz/foo

Answer the questions about your packages and you should see the new folder of your package is created. Now let's say our @nz/foo package will need to use the package @nz/hello. In your terminal type:

> lerna add @nz/hello@1.0.1 --scope=@nz/foo

The above will create a node_modules folder inside the foo folder with symlink to the @nz/hello package. You can also add packages not from your local packages folder, and just add packages from npm to your project. For example try and run:

> lerna add lodash --scope=@nz/foo

This will add the lodash package to your @nz/foo node_modules directory. Now let's try and update the @nz/hello to a new major update. change the file: packages/hello/lib/hello.js to this:

module.exports = hello;

function hello() {
    console.log('hello new major update');
}

Now commit your changes and run:

> lerna publish

Notice that whenever we push a new update to the @nz/hello package, the package the depends on that package @nz/foo will also be updated to a new version and the package.json of @nz/foo will be updated pointing to the new version of @nz/hello.

Summary

In the microservice world we have to start splitting our apps to different packages. Lerna is a great tool to manage all our packages in a monorepository where all the packages reside in a single folder. Now all we need is to create our packages and link them and we are good to go with a version controled npm packages of our infastructure.