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 viang 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!