why we abandoned Angular CLI in favor of Nx

Hello! My name is Daniel, I’m a front-end developer at Tinkoff Business. We build user-friendly interfaces so that customers can quickly register a business.

Today I want to talk about why we use Nx for all our Angular projects, what problems this tool solves and how it is better than Angular CLI.

What is Nx

Nx is a powerful build system that allows you to work with mono-repositories and offers a variety of tools and libraries. It is important to note that many developers use Nx not because of mono-repositories support, but because of features. For example, because of the tools configured out of the box.

Learn more about how to use Nx Online. And we will look at the following features by comparing Angular CLI and Nx:

  1. Managing monorepositories.

  2. Tools out of the box.

  3. Artifact caching.

  4. Migration to new versions of technologies.

Managing monorepositories

Why use monorepositories at all and what problems do they solve? Many articles have been written about this, but in short, there are several reasons:

  1. Reuse of common modules and components.

  2. Using common dependencies of the same versions.

  3. Use of common tools: testing, linting.

  4. Simplify integrations between projects.

Angular CLI. Does not offer a special approach for working in monorepositories. Theoretically, you can store all applications in Projects. For small projects, this may be sufficient, but scaling up can be problematic.

Nx. Nx is focused on mono-repositories, so there are a number of tools out of the box for convenient work with them:

— Project Boundaries. If a project is in a monorepository, it is possible that one project may import parts of another. Implicit dependencies between projects lead to a huge number of problems, including violation of SRP, high coupling, scaling and security difficulties.

To solve this problem, Nx offers the ESLint rule. It allows you to control access between projects, define clear boundaries between them, and enforce those boundaries. Details can be found Online.

– Dependency graph. Nx also offers a tool to visualize all the dependencies between projects and evaluate their impact on each other. The graph allows you to better understand the structure of the codebase, identify problems with implicit dependencies, and detect circular dependencies. An example graph can be seen on the project website.

Dependency graph generated by Nx

Dependency graph generated by Nx

Tools out of the box

Each new project is accompanied by the selection and configuration of standard tools for unit testing, integration testing, linting, and others.

Integrating a tool with a framework is not a trivial task, and sometimes developers spend a lot of time on it. Let’s take a look at what tools Angular CLI offers and what tools Nx offers.

Angular CLI. Now, when generating a project using the Angular CLI, we get only the application. Unit testing involves using Jasmine & Karma, but as of recent versions there is no config, and more recently Karma has become deprecated.

As for integration testing and linting, Protractor and TSLint are also deprecated, so they are not in the CLI. Angular CLI does not offer other alternatives out of the box.

Project generated via Angular CLI 15

Project generated via Angular CLI 15

You will most likely want to use ESLint at the very least. Then you have to find a tool and figure out what Angular ESlint is and how to start it. It’s easy, but you don’t want to face a problem already at the project generation stage.

If you decide to write unit tests, you will have to drag in the configuration. And if you want to move from Jasmine & Karma to Jest, you will have to figure out how to make Angular and Jest friends.

Integration testing is a little easier, but even in this case you will need to understand how to connect the tool and start it from scratch.

Nx. Nx has a set of generators that allow you to generate entities, add the necessary dependencies and tools, and carry out migrations in the project. For example, converting SCAM to Standalone components.

Now when you generate an Angular project with Nx, you get:

  • Angular application;

  • Jest for unit testing

  • Cypress for integration testing;

  • ESLint for linting;

  • Prettier for code formatting.

Project generated via Nx 15

Project generated via Nx 15

With the help of official generators, you can add other features: NgRx, Angular Universal, Module Federation support, Storybook, Tailwind and much more. The set of technologies supplied with the application allows you not to choose from an infinite number of libraries. This initial set can be controlled using flags when generating a project. For example, remove Jest or add Tailwind.

At the same time, no one forbids using your stack. You can manually configure custom packages or use list of community plugins for Nx, allowing you to add features to the project that are not in the official version. For example, stylelint, electron, ionic, playwright and others.

Artifact caching

Caching allows you to avoid recompiling unchanged files, which greatly speeds up the build process. It is present in both instruments. Let’s see what the difference is.

Angular CLI. Provides caching built on top of a Webpack solution. To simplify a lot, a hash is calculated for each file based on its contents. Thanks to this, you can keep track of which files have changed and only rebuild them.

The problem is that caching in Angular CLI is limited to builds and only one machine. Also, it’s slower than Nx.

For example, take a small component library and build it twice with Angular CLI.

Build results via Angular CLI

Build results via Angular CLI

Nx. In Nx, caching is not just a local assembly cache, but a cache of all operations. That is, builds, linting, tests, and any custom operations. Caching in Nx is built on top of Angular CLI caching, but with its own cache added on top of it all. So we just get an improved process from the Angular CLI.

Let’s get the same library with Nx. For the first build, the difference is insignificant: 10,545 versus 9027 ms. But as the project grows, the gap will increase. In the second case, thanks to improved caching, the difference is decent: 4902 versus 62 ms.

Build results via Nx

Build results via Nx

Nx Cloud

In addition to local caching, Nx offers Nx Cloud, which greatly reduces build times by caching build results remotely due to artifact sharing between build agents and machines.

The graph below shows how much time was saved with Nx Cloud over the last 30 days in the repository Nx.

Time saved with Nx Cloud at Nx

Time saved with Nx Cloud at Nx

The results are impressive: Nx Cloud saves more than half the time for all cached operations.

Let’s look at one more example: TaigaUI, UI Kit of our colleagues. In Taiga UI, only build- and test-operations are cached via Nx Cloud, so on the graph we see the saved time only for them. There is no caching for e2e and lint – it happened historically.

Time saved with Nx Cloud in Taiga UI

Time saved with Nx Cloud in Taiga UI

Here caching saves about 30-40% of the time. The performance is not as high as Nx, but partly it depends on the codebase and cached operations.

In any case, Nx Cloud can be connected with one command: this will not affect your workflow in any way, but you will save a lot of time.

You can read about caching on the Nx website. on this page And in this. And I talked in detail about Nx Cloud in the report our colleague Ivan Ishmametiev.

Migration to new versions of technologies

Technologies develop: something is added, something becomes deprecated, sometimes major product changes are required. All this leads to migrations – an integral part of development. Both Angular CLI and Nx offer migrations, but with different approaches.

Angular CLI. Migrations via the Angular CLI have a number of critical issues. They are discussed in detail in the official Nx documentationso I recommend reading it for completeness.

In short, Angular CLI updates everything at once. This may be unacceptable in large projects, as migrations generate a huge amount of changes that cannot be controlled. There is no possibility to migrate partially. As a result, we always have a huge PR and a high chance of breaking something.

One of the problems that is not mentioned in the documentation is that only Angular is automatically updated. That is, all related technologies – Jasmine, Protractor, NgRx – need to be updated manually or with separate third-party skematics.

Nx. Nx offers a two-step migration: upgrading in package.json and creating a migrations.json file that specifies the necessary changes. Developers choose which migrations to perform.

For example, we want to migrate from Angular 13 to Angular 14. We run nx migrate, we get the updated package.json and the list of required migrations. Then we ourselves choose what we want to migrate now and what not.

List of migrations generated by Nx

List of migrations generated by Nx

It is important to note that within the same migration and the same single command, Nx allows you to update all dependencies created through generators – linter, testing tools, state manager, and so on – to new versions.

NgRx migration generated by Nx

NgRx migration generated by Nx

Cypress migration generated by Nx

Cypress migration generated by Nx

Conclusion

Nx can be called a wrapper over the Angular CLI. By using Nx, you don’t lose anything, you only gain.

If you don’t work with monorepositories, Nx is useful for tools, migrations, and caching. If you work with mono-repositories, then in addition to the above features, you will also get convenient tools for working with them.

We at Tinkoff have completely switched to Nx, ceasing to support builders and skematics for the Angular CLI. Nx can do everything that Angular CLI can, but it adds a lot of features. And we don’t have to maintain two huge ecosystems.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *