Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (2023)

This is post 6 of 10 in the series “Module Federation”

  1. The Microfrontend Revolution: Module Federation in Webpack 5
  2. The Microfrontend Revolution: Module Federation with Angular
  3. Dynamic Module Federation with Angular
  4. Building A Plugin-based Workflow Designer With Angular and Module Federation
  5. Getting Out of Version-Mismatch-Hell with Module Federation
  6. Using Module Federation with (Nx) Monorepos and Angular
  7. Pitfalls with Module Federation and Angular
  8. Multi-Framework and -Version Micro Frontends with Module Federation: Your 4 Steps Guide
  9. Module Federation with Angular’s Standalone Components
  10. What’s New in our Module Federation Plugin 14.3?

Updated on 2021-08-08 for Angular and Nx 12.x and upwards
Updated on 2021-12-23 for Angular 13.x and Nx 13.4 and upwards
Updated on 2021-06-11 for Angular 14.x or higher and Nx 14.x

While it sounds like a contradiction, the combination of Micro Frontends and Monorepos can actually be quite tempting: No version conflicts by design, easy code sharing and optimized bundles are some of the benefits you get. Also, you can still deploy Micro Frontends separately and isolate them from each other.

This article compares the consequences of using several repositories ("Micro Frontends by the book") and one sole monorepo. After that, it shows with an example, how to use Module Federation in an Nx monorepo.

If you want to have a look at the 📂 source code used here, you can check out this repository.

Big thanks to the awesome Tobias Koppers who gave me valuable insights into this topic and to the one and only Dmitriy Shekhovtsov who helped me using the Angular CLI/webpack 5 integration for this.

Important: This article is written for Angular 14.x and higher. Hence, you also need Nx 14.2.x or higher. To find out about the small differences for lower versions of Angular and for the migration from such a lower version, please have a look to our migration guide.

Multiple Repos vs. Monorepos

I know, the discussion about using multiple repos vs. monorepos can be quite emotional. Different people made different experiences with both approaches. However, I can tell you: I’ve seen both working in huge real-world projects. Still, both comes with different consequences, I’m going to discuss in the following two section.

At the end of the day, you need to evaluate these consequences against your very project situation and goals. This is what software architecture is about.

Multiple Repositories: Micro Frontends by the Book

A traditional approach uses a separate repository per Micro Frontend:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (1)

This is also a quite usual for Micro Services and it provides the following advantages:

  • Micro Frontends — and hence the individual business domains — are isolated from each other. As there are no dependencies between them, different teams can evolve them separately.

  • Each team can concentrate on their Micro Frontend. They only need to focus on their very own repository.

    (Video) Angular Architekturen mit Nx Monorepos, Webpack Module Federation & Microfrontends | Manfred Steyer

  • Each team has the maximum amount of freedom in their repository. They can go with their very own architectural decisions, tech stacks, and build processes. Also, they decide by themselves when to update to newer versions.

  • Each Micro Frontend can be separately deployed.

As this best fits the original ideas of Micro Frontends, I call this approach "Micro Frontends by the book". However, there are also some disadvantages:

Of course, there are approaches to compensate for these drawbacks: For instance, we can automate the distribution of shared libraries to minimize the overhead. Also, we can avoid version conflicts by not sharing libraries between different Micro Frontends. Wrapping these Micro Frontends into web components further abstracts away the differences between frameworks.

While this prevents version conflicts, we still have increased bundle sizes. Also, we might need some workarounds here or there as Angular is not designed to work with another version of itself in the same browser window. Needless to say that there is no support by the Angular team for this idea.

If you find out that the advantages of this approach outweigh the disadvantages, you find a solution for mixing and matching different frameworks and versions here.

However, if you feel that the disadvantages weigh heavier, the next sections show an alternative.

Micro Frontends with Monorepos

Nearly all of the disadvantages outlined above can be prevented by putting all Micro Frontends into one sole monorepo:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (2)

Now, sharing libraries is easy and there is only one version of everything, hence we don’t end up with version conflicts in the browser. We can also keep some advantages outlined above:

  • Micro Frontends can be isolated from each other by using linting rules. They prevent one Micro Frontend from depending upon others. Hence, teams can separately evolve their Micro Frontend.

  • Micro Frontends can still be separately deployed.

Now, the question is, where’s the catch? Well, the thing is, now we are giving up some of the freedom: Teams need to agree on one version of dependencies like Angular and on a common update cycle for them. To put it in another way: We trade in some freedom to prevent version conflicts and increased bundle sizes.

One more time, you need to evaluate all these consequences for your very project. Hence, you need to know your architecture goals and prioritize them. As mentioned, I’ve seen both working in the wild in several projects. It’s all about the different consequences.

Monorepo Example

After discussing the consequences of the approach outlined here, let’s have a look at an implementation. The example used here is a Nx monorepo with a Micro Frontend shell (shell) and a Micro Frontend (mfe1, "micro frontend 1"). Both share a common library for authentication (auth-lib) that is also located in the monorepo. Also, mfe1 uses a library mfe1-domain-logic.

If you haven’t used Nx before, just assume a CLI workspace with tons additional features. You can find more infos on Nx in our tutorial.

(Video) Micro-Frontends with Module Federation using Angular and Nx

To visualize the monorepo’s structure, one can use the Nx CLI to request a dependency graph:

nx graph

If you don’t have installed this CLI, you can easily get it via npm (npm i -g nx). The displayed graph looks like this:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (3)

The auth-lib provides two components. One is logging-in users and the other one displays the current user. They are used by both, the shell and mfe1:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (4)

Also, the auth-lib stores the current user’s name in a service.

As usual in Nx and Angular monorepos, libraries are referenced with path mappings defined in tsconfig.base.json (Nx) or tsconfig.json (Angular CLI):

"paths": { "@demo/auth-lib": [ "libs/auth-lib/src/index.ts" ] },

The shell and mfe1 (as well as further Micro Frontends we might add in the future) need to be deployable in separation and loaded at runtime.

However, we don’t want to load the auth-lib twice or several times! Archiving this with an npm package is not that difficult. This is one of the most obvious and easy to use features of Module Federation. The next sections discuss how to do the same with libraries of a monorepo.

The Shared Lib

Before we delve into the solution, let’s have a look at the auth-lib. It contains an AuthService that logs-in the user and remembers them using the property _userName:

@Injectable({ providedIn: 'root' }) export class AuthService { // tslint:disable-next-line: variable-name private _userName: string = null; public get userName(): string { return this._userName; } constructor() { } login(userName: string, password: string): void { // Authentication for honest users // (c) Manfred Steyer this._userName = userName; } logout(): void { this._userName = null; } }

Besides this service, there is also a AuthComponent with the UI for logging-in the user and a UserComponent displaying the current user’s name. Both components are registered with the library’s NgModule:

@NgModule({ imports: [ CommonModule, FormsModule ], declarations: [ AuthComponent, UserComponent ], exports: [ AuthComponent, UserComponent ], }) export class AuthLibModule {}

As every library, it also has a barrel index.ts (sometimes also called public-api.ts) serving as the entry point. It exports everything consumers can use:

export * from './lib/auth-lib.module'; export * from './lib/auth.service'; // Don't forget about your components! export * from './lib/auth/auth.component'; export * from './lib/user/user.component';

Please note that index.ts is also exporting the two components although they are already registered with the also exported AuthLibModule. In the scenario discussed here, this is vital in order to make sure it’s detected and compiled by Ivy.

Let’s assume the shell is using the AuthComponent and mfe1 uses the UserComponent. As our goal is to only load the auth-lib once, this also allows for sharing information on the logged-in user.

The Module Federation Configuration

As in the previous article, we are using the @angular-architects/module-federation plugin to enable Module Federation for the shell and mfe1. For this, just run the following commands:

npm i @angular-architects/module-federation -D npm g @angular-architects/module-federation:init --project shell --port 4200 --type host npm g @angular-architects/module-federation:init --project mfe1 --port 4201 --type remote

Meanwhile, Nx also ships with its own support for Module Federation. Beyond the covers, it handles Module Federation in a very similar way as the plugin used here.

This generates a webpack config for Module Federation. Since version 14.3, the withModuleFederationPlugin provides a property sharedMappings. Here, we can register the monorepo internal libs we want to share at runtime:

// apps/shell/webpack.config.js const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); module.exports = withModuleFederationPlugin({ remotes: { 'mfe1': "http://localhost:4201/remoteEntry.js" }, shared: shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), sharedMappings: ['@demo/auth-lib'], });

As sharing is always an opt-in in Module Federation, we also need the same setting in the Micro Frontend’s configuration:

(Video) Beyond the basics of Module Federation micro frontends – Manfred Steyer

// apps/mfe1/webpack.config.js const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); module.exports = withModuleFederationPlugin({ name: "mfe1", exposes: { './Module': './apps/mfe1/src/app/flights/flights.module.ts', }, shared: shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), sharedMappings: ['@demo/auth-lib'], });

Since version 14.3, the Module Federation plugin shares all libraries in the monorepo by default. To get this default behavior, just skip the sharedMappings property. If you use it, only the mentioned libs are shared.

Trying it out

To try this out, just start the two applications. As we use Nx, this can be done with the following command:

nx run-many --target serve --all

The switch --all starts all applications in the monorepo. Instead, you can also go with the switch --projects to just start a subset of them:

nx run-many --target serve --projects shell,mfe1

--project takes a comma-separated list of project names. Spaces are not allowed.

After starting the applications, log-in in the shell and make it to load mfe1. If you see the logged-in user name in mfe1, you have the proof that auth-lib is only loaded once and shared across the applications.

Isolating Micro Frontends

One important goal of a Micro Frontend architecture is to isolate Micro Frontends from each other. Only if they don’t depend on each other, they can be evolved by autarkic teams. For this, Nx provides linting rules. Once in place, they give us errors when we directly reference code belonging to another Micro Frontend and hence another business domain.

In the following example, the shell tries to access a library belonging to mfe1:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (5)

To make these error messages appear in your IDE, you need eslint support. For Visual Studio Code, this can be installed via an extension.

Besides checking against linting rules in your IDE, one can also call the linter on the command line:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (6)

The good message: If it works on the command line, it can be automated. For instance, your build process could execute this command and prevent merging a feature into the main branch if these linting rules fail: No broken windows anymore.

For configuring these linting rules, we need to add tags to each app and lib in our monorepo. For this, you can adjust the project.json in the app’s or lib’s folder. For instance, the project.json for the shell can be found here: apps/shell/project.json. At the end, you find a property tag, I’ve set to scope:shell:

{ [...] "tags": ["scope:shell"] }

The value for the tags are just strings. Hence, you can set any possible value. I’ve repeated this for mfe1 (scope:mfe1) and the auth-lib (scope:auth-lib).

Once the tags are in place, you can use them to define constraints in your global eslint configuration (.eslintrc.json):

"@nrwl/nx/enforce-module-boundaries": [ "error", { "enforceBuildableLibDependency": true, "allow": [], "depConstraints": [ { "sourceTag": "scope:shell", "onlyDependOnLibsWithTags": ["scope:shell", "scope:shared"] }, { "sourceTag": "scope:mfe1", "onlyDependOnLibsWithTags": ["scope:mfe1", "scope:shared"] }, { "sourceTag": "scope:shared", "onlyDependOnLibsWithTags": ["scope:shared"] } ] } ]

After changing global configuration files like the .eslintrc.json, it’s a good idea to restart your IDE (or at least affected services of your IDE). This makes sure the changes are respected.

More on these ideas and their implementation with Nx can be found in my blog series on Strategic Design (Domain-driven Design) and Angular.

Incremental Builds

To build all apps, you can use Nx’ run-many command:

(Video) Micro Frontends with Angular using Module Federation

nx run-many --target build --all

However, this does not mean that Nx always rebuilds all the Micro Frontends as well as the shell. Instead, it only rebuilds the changed apps. For instance, in the following case mfe1 was not changed. Hence, only the shell is rebuilt:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (7)

Using the build cache to only recompile changed apps can dramatically speed up your build times.

This also works for testing, e2e-tests, and linting out of the box. If an application (or library) hasn’t been changed, it’s neither retested nor relinted. Instead, the result is taken from the Nx build cache.

By default, the build cache is located in node_modules/.cache/nx. However, there are several options for configuring how and where to cache.

Deploying

As normally, libraries don’t have versions in a monorepo, we should always redeploy all the changed Micro Frontends together. Fortunately, Nx helps with finding out which applications/ Micro Frontends have been changed or affected by a change:

nx print-affected --type app --select projects

You might also want to detect the changed applications as part of your build process.

Redeploying all applications that have been changed or affected by a (lib) change is vital, if you share libraries at runtime. If you have a release branch, it’s enough to just redeploy all apps that have been changed in this branch.

If you want to have a graphical representation of the changed parts of your monorepo, you can request a dependency graph with the following command:

nx affected:graph

Assuming we changed the domain-logic lib used by mfe1, the result would look as follows:

Using Module Federation with (Nx) Monorepos and Angular - ANGULARarchitects (8)

By default, the shown commands compare your current working directory with the main branch. However, you can use these commands with the switches --base and --head.

nx print-affected --type app --select projects --base branch-or-commit-a --head branch-or-commit-b

These switches take a commit hash or the name of a branch. In the latter case, the last commit of the mentioned branch is used for the comparison.

What’s next? More on Architecture!

So far, we’ve seen that Module Federation is a straightforward solution for creating Micro Frontends on top of Angular. However, when dealing with it, several additional questions come in mind:

  • According to which criteria can we sub-divide a huge application into micro frontends?
  • Which access restrictions make sense?
  • Which proven patterns should we use?
  • How can we avoid pitfalls when working with Module Federation?
  • Which advanced scenarios are possible?

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

Feel free to download it here now!

Conclusion

By using monorepos for Micro Frontends you trade in some freedom for preventing issues. You can still deploy Micro Frontends separately and thanks to linting rules provided by Nx Micro Frontends can be isolated from each other.

(Video) The Microfrontend Revolution: Using Webpack 5 Module Federation with Angular | Manfred Steyer

However, you need to agree on common versions for the frameworks and libraries used. Therefore, you don’t end up with version conflicts at runtime. This also prevents increased bundles.

Both works, however, both has different consequences. It’s on you to evaluate these consequences for your very project.

FAQs

How do you set up a micro frontend with Angular and NX? ›

Angular Tutorial
  1. 1 - Create Application.
  2. 2 - Add E2E Test.
  3. 3 - Display Todos.
  4. 4 - Connect to API.
  5. 5 - Add Node Application.
  6. 6 - Proxy Configuration.
  7. 7 - Share Code.
  8. 8 - Create Libraries.

What is module federation in Angular? ›

Module Federation allows loading separately compiled and deployed code (like micro frontends or plugins) into an application. This plugin makes Module Federation work together with Angular and the CLI.

What is dynamic module federation? ›

Dynamic Module Federation is a technique that allows an application to determine the location of its remote applications at runtime. It helps to achieve the use case of “Build once, deploy everywhere”.

What is NX Monorepos? ›

A monorepo is a single git repository that holds the source code for multiple applications and libraries, along with the tooling for them.

What is Micro frontend Angular? ›

in Angular / Micro FrontEnds / Frontend. 11/15/2021 12:00 AM. Micro Frontends (MFE) are the idea that a Single Page Application (SPA) can be divided into separate specialized sections that give independent teams end-to-end ownership. This gives development teams the autonomy to complete their work independently.

What is a micro front end? ›

Micro frontends are a new pattern where web application UIs (front ends) are composed from semi-independent fragments that can be built by different teams using different technologies. Micro-frontend architectures resemble back-end architectures where back ends are composed from semi-independent microservices.

How does module federation work? ›

Module Federation allows loading separately compiled applications at runtime. Also, we can share common dependencies. This also allows sharing common data like information on the current user or global filters.

What is module and component in Angular? ›

Typically module is a cohesive group of code which is integrated with the other modules to run your Angular apps. A module exports some classes, function and values from its code. The Component is a fundamental block of Angular and multiple components will make up your application.

What architecture does Angular use? ›

The core of the Angular framework architecture is Angular Component. Angular Component is the building block of every Angular application. Every angular application is made up of one more Angular Component. It is basically a plain JavaScript / Typescript class along with a HTML template and an associated name.

How do you implement a module Federation? ›

Step-by-step Implementation of Module Federation In Angular
  1. Project Setup.
  2. Update Angular configuration file // angular. json.
  3. Split The Starter Project Into the Other projects.
  4. Configure Webpack files webpack. config. ts.
  5. Add a shared library to hold Module Federation Operations.
  6. Dynamically Load Remote Containers.
Dec 23, 2021

When was Module Federation introduced? ›

Module Federation was created by Zack Jackson, a Webpack core maintainer himself, and was integrated as a flagship feature of Webpack 5 in October 2020.

What is Webpack used for? ›

This is why webpack exists. It's a tool that lets you bundle your JavaScript applications (supporting both ESM and CommonJS), and it can be extended to support many different assets such as images, fonts and stylesheets.

How do I add NX to Angular materials? ›

Install the angular material lib: yarn add @angular/material. To see the avaible commands from the nx console: nx list @angular/material. To add angular material to the default project: nx generate @angular/material:ng-add.

What is NX in Angular? ›

Nx Workspace is a tool suite designed to architect, build and manage monorepos at any scale. It has out-of-the-box support for multiple frontend frameworks like Angular and React as well as backend technologies including Nest, Next, and Express.

Is Siemens NX free? ›

Siemens Digital Industries Student Software

Siemens provides a robust selection of software for students, completely free.

What is NX Angular? ›

Nx is a smart, fast and extensible build system with first class monorepo support and powerful integrations. It has a powerful core and a rich plugin ecosystem.

What are elements in Angular? ›

Angular elements are Angular components packaged as custom elements (also called Web Components), a web standard for defining new HTML elements in a framework-agnostic way.

Videos

1. Manfred Steyer - Federated Angular: Micro Frontends with Module Federation
(JSWORLD Conference)
2. AngularAir - Using Module Federation in Angular v11 with Manfred Steyer
(AngularAir)
3. ngCopenhagen: Micro-Frontends with Module Federation: Beyond the Basics 🎄
(Angular Copenhagen)
4. Manfred Steyer - Sustainable Angular-Architectures - Free Exclusive Webinar
(NG-Poland)
5. Micro Frontends with Module Federation and Angular 12
(NG-Poland)
6. DDD Plugin for Nx: Solid Architectures With the Push of a Button
(Manfred Steyer)
Top Articles
Latest Posts
Article information

Author: Jamar Nader

Last Updated: 02/26/2023

Views: 6225

Rating: 4.4 / 5 (75 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Jamar Nader

Birthday: 1995-02-28

Address: Apt. 536 6162 Reichel Greens, Port Zackaryside, CT 22682-9804

Phone: +9958384818317

Job: IT Representative

Hobby: Scrapbooking, Hiking, Hunting, Kite flying, Blacksmithing, Video gaming, Foraging

Introduction: My name is Jamar Nader, I am a fine, shiny, colorful, bright, nice, perfect, curious person who loves writing and wants to share my knowledge and understanding with you.