Revolutionizing Frontend Development: Unleashing the Power of Microfrontends with Module Federation and Angular

Revolutionizing Frontend Development: Unleashing the Power of Microfrontends with Module Federation and Angular

Enhancing Scalability, Reusability, and Collaboration in Angular Applications through Microfrontend Architecture and Module Federation.

Introduction

A cutting-edge architectural strategy called micro frontends expands the idea of microservices to the frontend layer of web applications. Large apps are difficult to scale, maintain, and deploy since frontend development is frequently centralized in old monolithic systems. Micro frontends, on the other hand, separate the frontend layer into smaller, loosely linked components, each in charge of a particular feature or capability.

Micro frontends make it easier to scale and reuse code. To optimize resource allocation, teams can separately scale their components based on unique demands. Additionally, because components may be used throughout several projects or applications, code reuse is improved while fostering efficiency and uniformity.

Micro frontend implementation, however, needs thoughtful preparation and attention. Establishing common practices and standards as well as effective team cooperation become essential for ensuring consistent user experiences. A distributed frontend design may also make maintaining state, routing, and inter-component communication more difficult, demanding the usage of the right patterns and tools.

Module Federation

Modern JavaScript frameworks like Webpack 5 include a feature/plugin called module federation that enhances the idea of micro frontends. It enables smooth integration and cooperation between various frontend apps and micro frontends by enabling the dynamic runtime sharing of code between them.

Several Benefits

Code Sharing, Independent Development, Deployment, Seamless Integration, Technology Diversity, Scalability, and Incremental Migration.

We can obviously use other MicroFrontends frameworks such as Single SPA but it has disadvantages over Module Federation viz. Complexity (Learning Curve), Increased Tooling and Configuration, Performance Impact (Dynamic Loading and Lifecycle Management), Dependency Management, Centralized Development Model, and Limitations with Cross-Framework Communication.

Pre-requisites

  • NPM (for managing and installing dependencies in the project.)

  • Angular CLI (npm install -g @angular/cli)(Verify via ng version)

Setup Angular Workspace

Let's first create Angular Workspace via

ng new mf-workspace --create-application="false"

Workspace is a collection of Angular projects (that is, applications and libraries) powered by the Angular CLI that are typically co-located in a single source-control repository

Once the workspace is created, we can create the required projects(apps) such as Wrapper applications and multiple MicroFrontend Apps.

Setup Wrapper Application

Firstly we will set up the Wrapper application which will act as Holder or Host Application.

Let's use ng command to create an application as below named Wrapper

ng g application wrapper --routing --style=css

Within the application created, we will create a Home Component as below

ng g c home --project=wrapper

Post creation of the New Component named home our project structure should be like the one below.

Update Route Module with below, so that root of wrapper project goes to Home Component as below

Home Component HTML looks one below

Serve project Wrapper over HTTP with the below command ng serve wrapper

This will run the application locally on 4200 and we should be able to view as below

Setup MicroFrontEnd Application

We will now create again new Angular Application named mfe1 for simplicity

ng a application mfe1 --routing --style=css

Followed by its main component, for routing purposes

ng g c main --project mfe1

Post generation of application and Main Component our structure would like one below

We will now create an Angular Module named shared which can be exposed from MFE1 and consumed in the main Wrapper Application later as part of Module Federation.

ng g m shared --routing --project=mfe1

And then we will create component within the same module as below

ng g c shared --project=mfe1

We will now add Route with an empty path to the new Shared component in Shared Module File.

We will also update the App Routing module for our routing path to the lazy load shared module. We will start the MicroFrontEnd application individually to see if it works fine using ng serve mfe1.

The app-routing-module.ts within mfe1 application will look like below

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MainComponent } from './main/main.component';

const routes: Routes = [
  {
    path: '',
    component: MainComponent
  },
  {
    path: 'mfe1',
    loadChildren: () => import('./shared/shared.module').then((m) => m.SharedModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Serve application now with ng serve mfe1 we can see below again the 4200 port

Adding Module Federation Plugin

Angular CLI doesn't add Module Federation Webpack plugin out of the box, we can add it by executing below.

ng add @angular-architects/module-federation --project wrapper--port 4200 --skip-confirmation
ng add @angular-architects/module-federation --project mfe1 --port 7001 --skip-confirmation

This will create webpack(webpack.config.js etc.) configuration files, assign a port for the application to serve on, required skeleton for module federation in both angular applications as below

Wrapper Application Command

MFE1 Application Command

Webpack Configuration Changes

We will add the below resolutions(if you are using Angular 11, the default webpack will be version 4, so using resolutions we force custom package transitive dependency) in workspace package.json as below

"resolutions": {
    "webpack": "^5.4.0",
    "license-webpack-plugin": "2.3.17"
 },

When we add module federation plugin it auto generates lot of boiler plate which helps us expose or consume remotes in our MicroFrontend and Wrapper applications respectively like below

MicroFrontEnd Application Module Federation Changes

Open webpack.config.js from mfe1 project

We basically expose Shared Module and its components via this. And it will be loaded in the Wrapper application via remoteEntry.js with name mfe1. Add something below to ModuleFederationPlugin options as below

  name: "mfe1",
        filename: "remoteEntry.js",
        exposes: {
            './MfeSharedModule': './projects/mfe1/src/app/shared/shared.module.ts',
        },

That's it for the change of our MicroFrontEnd application.

Wrapper Application Module Federation Changes

There are multiple ways to load MicroFrontEnd apps into wrapper applications, we will use Dynamic Module Federation as it will become easy for environment agnostic load of Remote modules too.

We can do the same via Webpack config too.

We will update the Wrapper application Routing Module(wrapper/app-routing.module.ts) with below

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    pathMatch: 'full'
  },
  {
    path: "mfe1",
    loadChildren: () => loadRemoteModule({
      type: 'module',
      remoteEntry: 'http://localhost:7001/remoteEntry.js',
      exposedModule: './MfeSharedModule'
    }).then(m => m.SharedModule)
  }
];

This will basically load Entire Shared Module exposed and the Shared component within it over Remote Entry via the Remote Module function which is part of the Angular Architect Module Federation dependency we added.

Thats it for integration between host and MF applications, as quick as simple it is!

Now we serve both applications in different terminals via

ng serve wrapper 
ng serve mfe1

Now if we load Wrapper Application running at 4200, we can set our application as below

On Root('/') URL, we load the Home Component of the wrapper application, and on /mfe1 we load the Component from the remote Module loaded from the MicroFrontend Application mfe1

We can also access our standalone MicroFrontEnd application over 7001 as below

Thats it. Voila, we can now add more applications as MicroFrontEnd Application and develop, test, and deploy individually.

Resources


Thank you for reading, If you have reached it so far, please like the article, It will encourage me to write more such articles. Do share your valuable suggestions, I appreciate your honest feedback and suggestions!

I would love to connect with you on Twitter | LinkedIn

Did you find this article valuable?

Support Virendra Oswal by becoming a sponsor. Any amount is appreciated!