What Nx Provides

Nx Values

priorities

Productivity

Nx helps your team move quickly when setting up enterprise Angular applications by providing a default setup for complex projects. It adds the monorepo-style development to the Angular CLI, which enables fast project development, team collaboration, and code reuse. Nx also provides runtime libraries to simplify complex tasks with state management and testing, so developers can spend more time implementing features and less time wrestling with setup and testing. Finally, Nx provides an easy path for otherwise complex tasks, such as setting up AngularJS upgrade in hybrid mode for an iterative approach to upgrading applications.

Consistency

Out of the box, Angular CLI follows the Angular style guide and helps enforce patterns and practices within application folder/file structure, naming conventions, component organization and more, providing a good foundation for most applications. Nx builds on the foundation provided by Angular CLI, and provides a more opinionated architecture, which allows Nx to provide more advanced code generation and analysis. With stronger conventions around code organization and state management in place, teams are able to share more knowledge, code, and infrastructure.

Safety

The contributors to Nx have worked with many teams building massive Angular applications, and have found common mistakes and antipatterns which can lead to race conditions, performance issues, or code maintainability challenges. Fortunately, many of these mistakes can be identified by static analysis at development time.

What's in the box

  • Nx Workspace
  • Workspace-Specific Schematics
  • State Management
  • NgRx
  • Data Persistence
  • Linters
  • Code Formatter
  • UpgradeModule and dowgradeModule helpers

Nx Workspace

A workspace contains your Angular application (or applications) and any supporting libraries you create. It is a monorepo for your application domain.

Why should you use a monorepo?

With Angular CLI you can add different types of projects to a single workspace (by default you can add applications and libraries). This is great, but is not sufficient to enable the monorepo-style development. Nx adds an extra layer of tooling to make this possible.

Analyzing and Visualizing the Dependency Graph

To be able to support the monorepo-style development, the tools must know how different projects in your workspace depend on each other. Nx uses advanced code analysis to build this dependency graph.

nx workspace

You can visualize it by running npm run dep-graph or yarn dep-graph.

dependency-graph

You can also visualize what is affected by your change, by running npm run affected:dep-graph or yarn affected:dep-graph.

dependency-graph-affected

Imposing Constraints on the Dependency Graph

If you partition your code into well-defined cohesive units, even a small organization will end up with a dozen apps and dozens or hundreds of libs. If all of them can depend on each other freely, the chaos will ensue and the workspace will become unmanageable.

To help with that Nx uses code analyses to make sure projects can only depend on each other's well-defined public API. It also allows you to declaratively impose constraints on how projects can depend on each other.

Enterprise development teams love this capability to constrain library dependencies. With it developers can define which projects are team-specific and which are shared.

For instance, with this configuration, when we import private client code from the admin part of our repo, we will get an error.

"nx-enforce-module-boundaries": [
  true,
  {
    "allow": [],
    "depConstraints": [
       {  
          "sourceTag": "shared", 
          "onlyDependOnLibsWithTags": ["shared"]
       },
       { 
          "sourceTag": "admin", 
          "onlyDependOnLibsWithTags": ["shared", "admin" ] 
       },
       { 
          "sourceTag": "client", 
          "onlyDependOnLibsWithTags": ["shared", "client" ] 
       },
       { 
          "sourceTag": "*", 
          "onlyDependOnLibsWithTags": ["*"] 
       }
     ]
  }
]

dependency-graph-contraints-lint-error

With these dependency constraints, another team won't create a dependency on your internal library.

You can define which projects contain components, NgRx code, and features, so you, for instance, can disallow projects containing dumb UI components depend on NgRx. You can define which projects are experimental and which are stable, so stable applications cannot depend on experimental projects etc.

Implicit Dependencies

Nx uses its built-in intelligence to create the dependency graph of the apps and libs, and that gets used to figure out what needs to be rebuilt and retested. There are certain files, however, that Nx cannot analyze. That’s why Nx has support for implicit dependencies. They are defined in nx.json.

{
  "npmScope": "mycompany",
  "implicitDependencies": {
    "package.json": "*",
    "angular.json": "*",
    "tsconfig.json": "*",
    "tslint.json": "*",
    "nx.json": "*"
  },
  "projects": {}
}

These tell Nx that a change to files in this list will affect every single project.

Rebuilding and Retesting What is Affected

To be productive in a monorepo, you need to be able to check that your change is safe, and rebuilding and retesting everything on every change won't scale. Nx uses code analysis to determine what needs to be rebuild and retested.

yarn affected:build --base=master --head=HEAD # reruns build for all the projects affected by a PR
yarn affected:test --base=master --head=HEAD  # reruns unit tests for all the projects affected by a PR
yarn affected:e2e --base=master --head=HEAD # reruns e2e tests for all the projects affected by a PR

affected-test

Nx will topologically sort the projects, and will run what it can in parallel. You can also retest a project with all its direct and indirect dependencies, like this: ng test --project=myapp --with-deps.

When introducing a major change to a large codebase, we don’t want to retest all the projects affected over and over again. We probably want to retest only the ones that failed last time. We can use the --only-failed option for that:

yarn affected:build --base=master --only-failed
yarn affected:test --base=master --only-failed
yarn affected:lint --base=master --only-failed
yarn affected:e2e --base=master --only-failed

Most of the code changes in an Nx Workspace will only affect a handful of projects, so rebuilding and retesting them is usually quite fast. Some code changes, however, are large and can result in the whole repository being rebuilt. We can pass --parallel to make this process faster:

yarn affected:build --base=master --parallel
yarn affected:test --base=master --parallel
yarn affected:lint --base=master --parallel
yarn affected:e2e --base=master --parallel

We can also pass --maxParallel to specify the number of parallel processes.

Check out the Nx Workspace guide to get started with your own Nx Workspace

Workspace-Specific Schematics

Nx helps promote best practices.

Some of the them are well-established in the Angular community. For instance, most non-trivial Angular projects use NgRx, so Nx comes with a set of built-in code generators and runtime libraries to make sure your applications’ state management is consistent. Just run ng g ngrx accounts --module=one/two/app.module.ts to set everything up.

Some, however, are specific to your organization. But Nx can help with those as well.

Check out the Workspace-Specific Schematics guide to learn more.

State Management

Managing state is a hard problem. We need to coordinate multiple backends, web workers, and UI components, all of which update the state concurrently. NgRx provides a great solution to state management, but implementing it in a consistent way is left up to developers.

NgRx

Nx comes with code generators to create recommended implementation patterns for NgRx. These involve a root state for your application and feature state for additional modules you add over time to your application. The code generators handle setting up the files needed to implement state, complete with actions, reducers and effects along with specs for testing. These allow your team to follow a set pattern for state management implementation at the root and feature levels.

Check out the Setting up ngrx guide to start working with ngrx in an Nx Workspace.

NgRx and Data Persistence

Nx comes with utilities to simplify data persistence with NgRx (data fetching, optimistic and pessimistic updates). This code provides implementation patterns that can be repeated for common CRUD operations with network endpoints.

Check out the Data Persistence guide to learn how to handle fetching data in an Nx Workspace.

Linters

Since Nx provides an opinionated way of developing large Angular applications, it can safely provide code analysis to help developers ensure they're adhering to best practices. Nx ships TSLint rules that work with Angular CLI's ng lint command, and will also provide feedback in IDEs at development time. For example, if any module imports from a deep path from another library, Nx's linter will provide feedback that imports should only be imported from the top-level library name. This helps teams enforce strict public APIs between libraries, allowing for no surprises when libraries change their internal structure.

Code Formatter

Developers should spend more time focusing on how code works, less time on making sure their tabs, whitespace, and line endings are correct. So Nx provides a formatter to clean up your code in an idiomatic way for you. Nx's code formatter will run every time something new is generated with Angular CLI, or can be run manually by running npm run format:write or npm run format:check.

Upgrading an AngularJS app to Angular

Many organizations have large AngularJS 1.x applications deployed to production. These applications may be built by multiple teams from different lines of business. They may use different routers and state management strategies. Rewriting such applications all at once, or "big bang migrations", is not just impractical, it is often impossible, and mainly for business reasons.

The NgUpgrade module provided by Angular provides a solid story for migrating an existing AngularJS application to Angular, but the setup and implementation can be a lot of work. Nx helps to make that simple by providing a way to get started with the upgrade shell pattern, an approach of running an AngularJS application with Angular and providing a way to migrate over time.

Check out the AngularJS UpgradeModule and AngularJS downgradeModule guides to get started.

Looking for more best practices for enterprise-scale Angular development from the Nrwl team?

Visit Nx Playbook