1. Angular’s Future Without NgModules – Part 1: Lightweight Solutions Using Standalone Components
  2. Angular’s Future Without NgModules – Part 2: What Does That Mean for Our Architecture?
  3. 4 Ways to Prepare for Angular’s Upcoming Standalone Components

Angular’s Future Without NgModules – Part 2: What Does That Mean for Our Architecture?

For the grouping of related building blocks, simple barrels are ideal for small solutions. For larger projects, the transition to monorepos as offered by the CLI…

  1. Angular’s Future Without NgModules – Part 1: Lightweight Solutions Using Standalone Components
  2. Angular’s Future Without NgModules – Part 2: What Does That Mean for Our Architecture?
  3. 4 Ways to Prepare for Angular’s Upcoming Standalone Components

Update on 2022-05-01: Texts and examples fully updated to use initial Standalone Components support in Angular 14.0.0-next.15 (instead of just using a shim for simulating them).

In the first part of this short series, I’ve shown how Standalone Components will make our Angular applications more lightweight in the future. In this part, I’m discussing options for improving your architecture with them.

The 📂 source code for this can be found in the form of a traditional Angular CLI workspace (see several branches) and as an Nx workspace that uses libraries as a replacement for NgModules.

Grouping Building Blocks

Unfortunately, the examples shown in the first part of this series cannot keep up with one aspect of NgModules. Namely the possibility of grouping building blocks that are usually used together. The good news: EcmaScript with barrels offers a way of doing this. A barrel is an EcmaScript file that exports related elements.

These files are often called public-api.ts or index.ts. The example project used contains such an index.ts to group two navigation components from the shell folder:

Grouping two Standalone Components with a barrel

The barrel itself re-exports the two components:

export { NavbarComponent } from './navbar/navbar.component';
export { SidebarComponent } from './sidebar/sidebar.component';

// 8<---
// Workaround: Needed for the time beeing
import { NavbarComponent } from './navbar/navbar.component';
import { SidebarComponent } from './sidebar/sidebar.component';

export default [
    NavbarComponent,
    SidebarComponent   
];

As Standalone Components currently not allow to import a whole barrel (all experts of a barrel), we need a workaround: An array containing all the exports. In the example shown, this array is the default export.

It’s needless to say that this workaround comes with a lot of redundant code hence the Angular team already discusses ways to get rid of it. I’m going to update this blog post, once we have a better solution.

The exported array can now be spread into the imports array:

import shell from '../../../../shell';

@Component ({
  standalone: ​​true,
  selector: 'app-my-cmp',
  imports: [
    ...shell,
    [...]
  ]
})
export class MyComponent {
}

This solution can be designed even more elegantly by giving the barrel a path mapping via the TypeScript configuration (tsconfig.json in the project’s root):

"paths": {
 "@demo/shell": ["src/app/shell/index.ts"],
  [...]
}

This allows direct access to the barrel using a well-defined name without having to worry about – sometimes excessive – relative paths:

// Import via mapped path:
import shell from '@demo/shell';

@Component ({
  standalone: ​​true,
  selector: 'app-root',
  imports: [
    ...shell
  ]
})
export class AppComponent {
}

The Next Logical Step: Workspace Libraries and Nx

These path mappings can of course be created manually. However, it is a little easier with the CLI extension Nx which automatically generates such path mappings for each library created within a workspace. Libraries seem to be the better solution anyway, especially since they subdivide it more and Nx prevents bypassing the barrel of a library.

This means that every library consists of a public — actually published — and a private part. The library’s public and private APIs are also mentioned here. Everything the library exports through its barrel is public. The rest is private and therefore a "secret" of the library that other parts of the application cannot access.

It is precisely these types of "secrets" that are a simple but effective key to stable architectures, especially since everything that is not published can easily be changed afterwards. The public API, on the other hand, should only be changed with care, especially since a breaking change can cause problems in other areas of the project.

An Nx project (workspace) that represents the individual sub-areas of the Angular solution as libraries could use the following structure:

Structure of an Nx Solution

Each library receives a barrel that reflects the public API. The prefixes in the library names reflect a categorization recommended by the Nx team. For example, feature libraries contain smart components that know the use cases, while UI libraries contain reusable dumb components. The domain library comes with the client-side view of our domain model and the services operating on it, and utility libraries contain general auxiliary functions.

On the basis of such categories, Nx allows the definition of linting rules that prevent undesired access between libraries. For example, you could specify that a domain library should only have access to utility libraries and not to UI libraries:

Nx prevents unwanted access between libraries via linting

In addition, Nx allows the dependencies between libraries to be visualized:

Nx visualizes the dependencies between libraries

If you want to see all of this in action, feel free to have a look at the Nx version of the example used here. Your find the 📂 Source Code at GitHub.

Conclusion

Standalone Components make the future of Angular applications more lightweight. We don’t need NgModules anymore. Instead, we just use EcmaScript modules. This makes Angular solutions more straightforward and lowers the entry barrier into the world of the framework. Thanks to the mental model, which regards standalone components as a combination of a component and a NgModule, this new form of development remains compatible with existing code.

For the grouping of related building blocks, simple barrels are ideal for small solutions. For larger projects, the transition to monorepos as offered by the CLI extension Nx seems to be the next logical step. Libraries subdivide the overall solution here and offer public APIs based on barrels. In addition, dependencies between libraries can be visualized and avoided using linting.

What’s next? More on Architecture!

So far, we’ve seen that Nx can help to structure Angular-based applications and that it’s concepts fit perfectly to the new world of Standalone Components. However, when dealing with Nx, several additional questions come in mind:

  • According to which criteria can we sub-divide a huge application into libraries and sub-domains?
  • Which access restrictions make sense?
  • Which proven patterns should we use?
  • How can we evolve our solution towards micro frontends?

Our free eBook (about 100 pages) covers all these questions and more:

free ebook

Feel free to download it here now!

Don't Miss Anything!


Subscribe to our newsletter to get all the information about Angular.


* By subscribing to our newsletter, you agree with our privacy policy.

Unsere Angular-Schulungen

  1. Angular’s Future Without NgModules – Part 1: Lightweight Solutions Using Standalone Components
  2. Angular’s Future Without NgModules – Part 2: What Does That Mean for Our Architecture?
  3. 4 Ways to Prepare for Angular’s Upcoming Standalone Components

Aktuelle Blog-Artikel

  1. Angular’s Future Without NgModules – Part 1: Lightweight Solutions Using Standalone Components
  2. Angular’s Future Without NgModules – Part 2: What Does That Mean for Our Architecture?
  3. 4 Ways to Prepare for Angular’s Upcoming Standalone Components

Nur einen Schritt entfernt!

Stellen Sie noch heute Ihre Anfrage,
wir beraten Sie gerne!

Jetzt anfragen!