How Nx and a Monorepo Helped My Team Succeed

Jason Warner
ngconf

--

My team is currently working on a project to upgrade an AngularJS 1.5 application to Angular. This project started two years ago when I joined Fidelis Cybersecurity. My original assignment was to create a feature that would allow users to connect to a computer through a terminal hosted in a browser. I needed to add the terminal to an existing application using AngularJS 1.5.

I am competent at Angular, but I am very rusty with AngularJS. The obvious choice at the time was to create a web component. Management pushed back almost immediately. There was already one other web component in the project, which led to frustration among the team when implementing change requests. I assured everyone that it would not be frustrating or difficult this time. I was confident because I had a secret weapon.

I could be confident because I was using Nx from Nrwl to create a monorepo. Using this approach, we could quickly pivot if problems made using a web component complicated. The monorepo proved to be a good decision almost immediately. The project owner asked for a new requirement during the feature development — the ability to display the embedded component in a new browser window.

The terminal in the application and a new browser window.

Code Sharing is Key

To create the popout feature, we needed to host the terminal component in another application. We had two choices. We could create a shell in AngularJS to host the web component or create a host application in Angular. The team agreed that using Angular to host the feature was the right decision because we wanted to upgrade from AngularJS.

The traditional model required a new application for the Angular Shell. That meant creating a new git repository and some way for the repository to share the terminal component. The easiest route was to use the existing web component. However, using the web component has the downside of bootstrapping Angular twice — once for the host application and a second time for the web component. So another approach is to create a locally hosted npm package that contains the terminal component. Then we could use that npm package in the web component and the new Angular application.

Because we had a monorepo, we didn’t have to do either. We created a library using Nx. Then we moved the terminal component into this new library. We already had an application for the web component. For the Angular shell, we added a new application. Nx enforces boundaries that you create between applications and libraries. This feature ensures that the new application can’t access the web component. However, it can access the new library. This separation guarantees that we won’t try to access the web component application code from new applications.

Having a monorepo and excellent tools allowed us to make this change quickly. This speed allowed us to add two new features with relative ease. The first was the ability to browse the file system on a remote computer. We wanted a user to delete files, copy files locally, or quarantine potentially dangerous files. The second new feature was a way to view processes running on a remote computer. A user could get information about the process tree, create rules from the running process, kill the process, or even the entire process tree. Unfortunately, these new features uncovered a new problem.

Nx Provides Tools for Upgrading AngularJS

Our web components had almost reached their limit. We decided not to use zone.js due to some articles written about Angular Elements. Unfortunately, we kept forgetting to inject and use the ChangeDetectorRef. Our forgetfulness led to strange bugs when a user interacted with our features. We also experienced performance issues because our web components were getting bigger and taking longer to bootstrap. We needed a new solution.

While doing research, we discovered that Nx includes a tool to help create a downgradeModule. This tool uses best practices for downgradeModule and generates a helpful file hierarchy. With a downgradeModule, we could replace our existing web components with minimal work. We could also reinstate zone.js, fixing our change detection issues. Finally, we could bootstrap Angular and our components only once when the application loads. Because we had a monorepo, we could work on this new feature in parallel with the existing web component deployment.

The move to the downgradeModule was seamless and very successful. It went so well that most of the team began developing features in Angular for the downgradeModule. Unfortunately, our success led to our current concern. The downgradeModule is so large that we need to split it using lazy-loading to improve performance.

Libraries in the downgradeModule

To facilitate lazy-loading, we are changing our application paradigm again. We are going to host our AngularJS application inside of a new Angular application using UpgradeModule. Once again, Nx has a tool to make this process easier. Because every feature is in a library, lazy-loading is simple. First, we remove the reference from the AppModule and then add a lazy-loaded child route.

The reason every feature is in its own library is that a monorepo in Angular makes choosing libraries an easy choice. It is so easy to add and use libraries that we rarely add new modules that aren’t in a library. In addition, libraries provide many benefits. For example, we can easily share code between libraries and applications. We can efficiently build a publishable library thanks to Nx(to share code with the rest of the company), to name a few.

Other Tools From Nx

Nx has many valuable tools for Angular. Using these tools benefits our entire codebase because of the monorepo. A great example of this was when we converted from TSLint to ESLint. Palantir deprecated TSLint in 2019. We were never really successful in converting from TSLint to ESLint. Every time we tried, we wound up with concerns that were difficult to resolve. Our monorepo was growing and didn’t follow the typical layout patterns in the blogs discussing how to upgrade. Nx includes a tool that upgraded our TSLint to ESLint on the first attempt. It was a colossal win getting away from the old TSLint rules.

There have been other great wins, like being able to use Jest for testing our Angular libraries. In addition, Nx is constantly updating with best practices, which are easy to implement into our existing monorepo and Nx workspace. Most of the time, upgrades to the next version of Nx include new features and best practices with migrations to make the changes for you.

Downsides to Using a Monorepo

There are some downsides to using a monorepo. First, you can only have one package.json per project. For some teams, this is an issue. I have not had a problem, but I recognize why organizations might not like this restriction.

Second, changing a library requires all apps and libraries that rely on that library to change. If you want to have an application that depends on a different version of your library, you will need to find a solution.

Third, a monorepo makes controlling access to certain apps or libraries more difficult. In most scenarios with a monorepo, you check out the entire repository, including every app and library in the repo.

Finally, the size of the monorepo can be a concern. A large monorepo can lead to slower build times, more memory consumption, source control problems or more disk space consumption. Due to the size of our monorepo, I have not experienced these issues with Angular and Nx, but they are a concern.

I find the advantages of using a monorepo far outweigh the potential downsides. I know that companies like Google have gigantic codebases in a monorepo. Using a monorepo makes a lot of sense when working with Angular. I recommend them to anyone as a great way to organize code and help your team be successful by sharing code and delivering features more rapidly.

Now that you’ve read this article and learned a thing or two (or ten!), let’s kick things up another notch!

Take your skills to a whole new level by joining us in person for the world’s first MAJOR Angular conference in over 2 years! Not only will You be hearing from some of the industry’s foremost experts in Angular (including the Angular team themselves!), but you’ll also get access to:

  • Expert panels and Q&A sessions with the speakers
  • A friendly Hallway Track where you can network with 1,500 of your fellow Angular developers, sponsors, and speakers alike.
  • Hands-on workshops
  • Games, prizes, live entertainment, and be able to engage with them and a party you’ll never forget

We’ll see you there this August 29th-Sept 2nd, 2022. Online-only tickets are available as well.

https://2022.ng-conf.org/

--

--

Jason Warner
ngconf
Writer for

I enjoy everything related to code and being a dev. However, my only skills are showing up and being lucky and I'm not sure if luck is a talent.