Angular MFE Module Federation Setup | Complete Configuration Guide
This guide walks you through configuring Webpack Module Federation for your Angular Micro Frontend applications, enabling them to share code and components at runtime.
π― Module Federation Overview
Section titled βπ― Module Federation OverviewβModule Federation is a Webpack 5 feature that allows multiple separate builds to form a single application. It enables:
- Runtime Code Sharing: Load modules from other applications at runtime
- Independent Deployment: Each MFE can be deployed separately
- Shared Dependencies: Avoid duplicating common libraries
- Dynamic Imports: Load remote modules on-demand
Key Concepts
Section titled βKey Conceptsβ- Host: Application that consumes remote modules (your main shell app)
- Remote: Application that exposes modules to be consumed
- Federated Modules: Components/modules shared between applications
- Shared Dependencies: Libraries shared to prevent duplication
π οΈ Step 1: Install Module Federation Dependencies
Section titled βπ οΈ Step 1: Install Module Federation Dependenciesβ1.1 Install Angular Architects Module Federation
Section titled β1.1 Install Angular Architects Module FederationβFor each application (host and all remotes), install the required packages:
Unix/macOS/Windows:
# Navigate to each project and run:npm install @angular-architects/module-federation --save-dev
# Alternative: Install specific versionnpm install @angular-architects/module-federation@^17.0.0 --save-dev1.2 Install Supporting Dependencies
Section titled β1.2 Install Supporting DependenciesβUnix/macOS/Windows:
# Additional webpack dependenciesnpm install @angular-builders/custom-webpack --save-devnpm install webpack --save-devnpm install webpack-cli --save-devπ Step 2: Configure Host Application
Section titled βπ Step 2: Configure Host ApplicationβLetβs start by configuring the host application (host-banking-app):
2.1 Add Module Federation to Host
Section titled β2.1 Add Module Federation to HostβUnix/macOS:
cd host-banking-app
# Add module federation schematicng add @angular-architects/module-federation --type host --port 4200Windows:
Set-Location host-banking-app
# Add module federation schematicng add @angular-architects/module-federation --type host --port 4200This command will:
- Install necessary dependencies
- Create
webpack.config.js - Update
angular.json - Modify project configuration
2.2 Configure Host Webpack Config
Section titled β2.2 Configure Host Webpack ConfigβThe generated webpack.config.js should look like this:
const ModuleFederationPlugin = require("@module-federation/webpack");
module.exports = { mode: "development", plugins: [ new ModuleFederationPlugin({ name: "host", filename: "remoteEntry.js",
remotes: { "mfeLoanCalculator": "http://localhost:4201/remoteEntry.js", "mfeUserDashboard": "http://localhost:4202/remoteEntry.js", "mfeTransactionHistory": "http://localhost:4203/remoteEntry.js", },
shared: { "@angular/core": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/router": { singleton: true, strictVersion: true, requiredVersion: "auto" }, }, }), ],};2.3 Update Angular.json for Host
Section titled β2.3 Update Angular.json for HostβThe angular.json should be updated to use custom webpack:
{ "projects": { "host-banking-app": { "architect": { "build": { "builder": "@angular-builders/custom-webpack:browser", "options": { "customWebpackConfig": { "path": "./webpack.config.js" } } }, "serve": { "builder": "@angular-builders/custom-webpack:dev-server", "configurations": { "production": { "buildTarget": "host-banking-app:build:production" }, "development": { "buildTarget": "host-banking-app:build:development", "port": 4200 } } } } } }}2.4 Create MFE Manifest (Dynamic Configuration)
Section titled β2.4 Create MFE Manifest (Dynamic Configuration)βCreate src/assets/mf.manifest.json for dynamic remote configuration:
{ "mfeLoanCalculator": "http://localhost:4201/remoteEntry.js", "mfeUserDashboard": "http://localhost:4202/remoteEntry.js", "mfeTransactionHistory": "http://localhost:4203/remoteEntry.js"}π― Step 3: Configure Remote Applications
Section titled βπ― Step 3: Configure Remote ApplicationsβNow letβs configure each remote MFE:
3.1 Configure Loan Calculator MFE
Section titled β3.1 Configure Loan Calculator MFEβUnix/macOS:
cd mfe-loan-calculator
# Add module federation as remoteng add @angular-architects/module-federation --type remote --port 4201Windows:
Set-Location mfe-loan-calculator
# Add module federation as remoteng add @angular-architects/module-federation --type remote --port 42013.2 Configure Loan Calculator Webpack
Section titled β3.2 Configure Loan Calculator WebpackβUpdate webpack.config.js in mfe-loan-calculator:
const ModuleFederationPlugin = require("@module-federation/webpack");
module.exports = { mode: "development", plugins: [ new ModuleFederationPlugin({ name: "mfeLoanCalculator", filename: "remoteEntry.js",
exposes: { "./LoanCalculatorModule": "./src/app/loan-calculator/loan-calculator.module.ts", "./LoanCalculatorComponent": "./src/app/loan-calculator/loan-calculator.component.ts", },
shared: { "@angular/core": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/router": { singleton: true, strictVersion: true, requiredVersion: "auto" }, }, }), ],};3.3 Create Loan Calculator Module
Section titled β3.3 Create Loan Calculator ModuleβCreate a dedicated module for the loan calculator:
Unix/macOS/Windows:
ng generate module loan-calculator --routingloan-calculator.module.ts:
import { NgModule } from '@angular/core';import { CommonModule } from '@angular/common';import { FormsModule } from '@angular/forms';import { RouterModule } from '@angular/router';
import { LoanCalculatorRoutingModule } from './loan-calculator-routing.module';import { LoanCalculatorComponent } from './loan-calculator.component';
@NgModule({ declarations: [ LoanCalculatorComponent ], imports: [ CommonModule, FormsModule, LoanCalculatorRoutingModule ], exports: [ LoanCalculatorComponent ]})export class LoanCalculatorModule { }loan-calculator-routing.module.ts:
import { NgModule } from '@angular/core';import { RouterModule, Routes } from '@angular/router';import { LoanCalculatorComponent } from './loan-calculator.component';
const routes: Routes = [ { path: '', component: LoanCalculatorComponent }];
@NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule]})export class LoanCalculatorRoutingModule { }3.4 Configure User Dashboard MFE
Section titled β3.4 Configure User Dashboard MFEβUnix/macOS:
cd mfe-user-dashboard
# Add module federationng add @angular-architects/module-federation --type remote --port 4202Windows:
Set-Location mfe-user-dashboard
# Add module federationng add @angular-architects/module-federation --type remote --port 4202webpack.config.js for user dashboard:
const ModuleFederationPlugin = require("@module-federation/webpack");
module.exports = { mode: "development", plugins: [ new ModuleFederationPlugin({ name: "mfeUserDashboard", filename: "remoteEntry.js",
exposes: { "./UserDashboardModule": "./src/app/user-dashboard/user-dashboard.module.ts", "./UserDashboardComponent": "./src/app/user-dashboard/user-dashboard.component.ts", },
shared: { "@angular/core": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/router": { singleton: true, strictVersion: true, requiredVersion: "auto" }, }, }), ],};Create corresponding module files similar to the loan calculator.
3.5 Configure Transaction History MFE
Section titled β3.5 Configure Transaction History MFEβUnix/macOS:
cd mfe-transaction-history
# Add module federationng add @angular-architects/module-federation --type remote --port 4203Windows:
Set-Location mfe-transaction-history
# Add module federationng add @angular-architects/module-federation --type remote --port 4203Follow the same pattern for webpack configuration and module creation.
π Step 4: Configure Host to Load Remotes
Section titled βπ Step 4: Configure Host to Load Remotesβ4.1 Update Host App Routing
Section titled β4.1 Update Host App RoutingβUpdate app-routing.module.ts in the host application:
import { NgModule } from '@angular/core';import { RouterModule, Routes } from '@angular/router';import { loadRemoteModule } from '@angular-architects/module-federation';
const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: 'dashboard', loadChildren: () => loadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:4202/remoteEntry.js', exposedModule: './UserDashboardModule' }).then(m => m.UserDashboardModule) }, { path: 'loan-calculator', loadChildren: () => loadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:4201/remoteEntry.js', exposedModule: './LoanCalculatorModule' }).then(m => m.LoanCalculatorModule) }, { path: 'transactions', loadChildren: () => loadRemoteModule({ type: 'module', remoteEntry: 'http://localhost:4203/remoteEntry.js', exposedModule: './TransactionHistoryModule' }).then(m => m.TransactionHistoryModule) }];
@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule]})export class AppRoutingModule { }4.2 Create Navigation in Host App
Section titled β4.2 Create Navigation in Host AppβUpdate app.component.html in the host application:
<div class="app-container"> <header class="app-header"> <nav class="navbar"> <div class="nav-brand"> <h1>π¦ Banking Platform</h1> </div> <ul class="nav-links"> <li><a routerLink="/dashboard" routerLinkActive="active">Dashboard</a></li> <li><a routerLink="/loan-calculator" routerLinkActive="active">Loan Calculator</a></li> <li><a routerLink="/transactions" routerLinkActive="active">Transactions</a></li> </ul> </nav> </header>
<main class="app-content"> <router-outlet></router-outlet> </main>
<footer class="app-footer"> <p>© 2024 Banking Platform - Powered by Micro Frontends</p> </footer></div>app.component.scss:
.app-container { min-height: 100vh; display: flex; flex-direction: column;}
.app-header { background: #2c3e50; color: white; padding: 0;
.navbar { display: flex; justify-content: space-between; align-items: center; padding: 1rem 2rem; max-width: 1200px; margin: 0 auto;
.nav-brand h1 { margin: 0; font-size: 1.5rem; }
.nav-links { display: flex; list-style: none; margin: 0; padding: 0; gap: 2rem;
li a { color: white; text-decoration: none; padding: 0.5rem 1rem; border-radius: 4px; transition: background-color 0.3s;
&:hover, &.active { background-color: #34495e; } } } }}
.app-content { flex: 1; padding: 2rem; max-width: 1200px; margin: 0 auto; width: 100%; box-sizing: border-box;}
.app-footer { background: #34495e; color: white; text-align: center; padding: 1rem; margin-top: auto;}
@media (max-width: 768px) { .navbar { flex-direction: column; gap: 1rem;
.nav-links { gap: 1rem; } }
.app-content { padding: 1rem; }}π§ Step 5: Dynamic Configuration Service
Section titled βπ§ Step 5: Dynamic Configuration Serviceβ5.1 Create MFE Configuration Service
Section titled β5.1 Create MFE Configuration ServiceβCreate a service to dynamically load MFE configurations:
Unix/macOS:
cd host-banking-appng generate service services/mfe-configWindows:
Set-Location host-banking-appng generate service services/mfe-configmfe-config.service.ts:
import { Injectable } from '@angular/core';import { HttpClient } from '@angular/common/http';import { Observable } from 'rxjs';
export interface MfeConfig { [key: string]: string;}
@Injectable({ providedIn: 'root'})export class MfeConfigService {
constructor(private http: HttpClient) { }
loadMfeConfig(): Observable<MfeConfig> { return this.http.get<MfeConfig>('/assets/mf.manifest.json'); }
async loadRemoteModule(remoteName: string, exposedModule: string) { const config = await this.loadMfeConfig().toPromise(); const remoteEntry = config![remoteName];
if (!remoteEntry) { throw new Error(`Remote ${remoteName} not found in configuration`); }
return import(/* webpackIgnore: true */ remoteEntry).then(() => { return (window as any)[remoteName]; }); }}5.2 Create Dynamic Route Loading
Section titled β5.2 Create Dynamic Route LoadingβCreate a utility for dynamic route loading:
import { loadRemoteModule } from '@angular-architects/module-federation';
export interface RemoteModuleConfig { remoteEntry: string; exposedModule: string; moduleName: string;}
export function loadDynamicRemoteModule(config: RemoteModuleConfig) { return () => loadRemoteModule({ type: 'module', remoteEntry: config.remoteEntry, exposedModule: config.exposedModule }).then(m => m[config.moduleName]);}π§ͺ Step 6: Testing Module Federation Setup
Section titled βπ§ͺ Step 6: Testing Module Federation Setupβ6.1 Start All Applications
Section titled β6.1 Start All ApplicationsβCreate comprehensive test scripts for your platform:
Unix/macOS (test-mfe.sh):
#!/bin/bash
echo "π Starting all MFE applications for testing..."
# Function to start an application in backgroundstart_app() { local app_name=$1 local port=$2
echo "Starting $app_name on port $port..." cd $app_name npm start > ../logs/$app_name.log 2>&1 & local pid=$! echo $pid > ../logs/$app_name.pid cd .. echo "$app_name started with PID $pid"}
# Create logs directorymkdir -p logs
# Start all applicationsstart_app "mfe-loan-calculator" 4201start_app "mfe-user-dashboard" 4202start_app "mfe-transaction-history" 4203start_app "host-banking-app" 4200
echo ""echo "π All applications started!"echo ""echo "π± Application URLs:"echo " Host App: http://localhost:4200"echo " Loan Calculator: http://localhost:4201"echo " User Dashboard: http://localhost:4202"echo " Transaction History: http://localhost:4203"echo ""echo "β³ Waiting for applications to start..."sleep 10
echo "π§ͺ Testing remoteEntry.js files..."curl -s -o /dev/null -w "%{http_code}" http://localhost:4201/remoteEntry.jscurl -s -o /dev/null -w "%{http_code}" http://localhost:4202/remoteEntry.jscurl -s -o /dev/null -w "%{http_code}" http://localhost:4203/remoteEntry.js
echo ""echo "β
Module Federation setup test complete!"echo "Press any key to stop all applications..."read -n 1
# Stop all applicationsfor pidfile in logs/*.pid; do if [ -f "$pidfile" ]; then pid=$(cat "$pidfile") kill $pid 2>/dev/null rm "$pidfile" fidone
echo "π All applications stopped."Windows (test-mfe.ps1):
Write-Host "π Starting all MFE applications for testing..." -ForegroundColor Green
# Function to start an application in backgroundfunction Start-App { param( [string]$AppName, [int]$Port )
Write-Host "Starting $AppName on port $Port..." -ForegroundColor Yellow Set-Location $AppName $process = Start-Process npm -ArgumentList "start" -PassThru -WindowStyle Hidden -RedirectStandardOutput "..\logs\$AppName.log" -RedirectStandardError "..\logs\$AppName.log" $process.Id | Out-File -FilePath "..\logs\$AppName.pid" Set-Location .. Write-Host "$AppName started with PID $($process.Id)" -ForegroundColor Green return $process}
# Create logs directoryNew-Item -Path "logs" -ItemType Directory -Force | Out-Null
# Start all applications$loanCalcProcess = Start-App "mfe-loan-calculator" 4201$dashboardProcess = Start-App "mfe-user-dashboard" 4202$transactionProcess = Start-App "mfe-transaction-history" 4203$hostProcess = Start-App "host-banking-app" 4200
Write-Host ""Write-Host "π All applications started!" -ForegroundColor GreenWrite-Host ""Write-Host "π± Application URLs:" -ForegroundColor CyanWrite-Host " Host App: http://localhost:4200"Write-Host " Loan Calculator: http://localhost:4201"Write-Host " User Dashboard: http://localhost:4202"Write-Host " Transaction History: http://localhost:4203"Write-Host ""Write-Host "β³ Waiting for applications to start..." -ForegroundColor YellowStart-Sleep -Seconds 10
Write-Host "π§ͺ Testing remoteEntry.js files..." -ForegroundColor Bluetry { $response1 = Invoke-WebRequest -Uri "http://localhost:4201/remoteEntry.js" -UseBasicParsing; Write-Host "Loan Calculator: $($response1.StatusCode)" } catch { Write-Host "Loan Calculator: Error" }try { $response2 = Invoke-WebRequest -Uri "http://localhost:4202/remoteEntry.js" -UseBasicParsing; Write-Host "User Dashboard: $($response2.StatusCode)" } catch { Write-Host "User Dashboard: Error" }try { $response3 = Invoke-WebRequest -Uri "http://localhost:4203/remoteEntry.js" -UseBasicParsing; Write-Host "Transaction History: $($response3.StatusCode)" } catch { Write-Host "Transaction History: Error" }
Write-Host ""Write-Host "β
Module Federation setup test complete!" -ForegroundColor GreenRead-Host "Press Enter to stop all applications"
# Stop all applicationsStop-Process -Id $loanCalcProcess.Id -Force -ErrorAction SilentlyContinueStop-Process -Id $dashboardProcess.Id -Force -ErrorAction SilentlyContinueStop-Process -Id $transactionProcess.Id -Force -ErrorAction SilentlyContinueStop-Process -Id $hostProcess.Id -Force -ErrorAction SilentlyContinue
Write-Host "π All applications stopped." -ForegroundColor Yellow6.2 Manual Testing Steps
Section titled β6.2 Manual Testing Stepsβ-
Start Applications:
Unix/macOS:
Terminal window chmod +x test-mfe.sh./test-mfe.shWindows:
Terminal window # Enable script execution if neededSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser# Run the test script.\test-mfe.ps1 -
Verify Remote Entries:
-
Test Host Application:
- Navigate to http://localhost:4200
- Click on each navigation link
- Verify MFEs load correctly
6.3 Debug Common Issues
Section titled β6.3 Debug Common IssuesβIssue 1: RemoteEntry.js not found
Unix/macOS:
# Check if remote is runningcurl http://localhost:4201/remoteEntry.js
# Verify webpack configurationnpm run build -- --stats-error-detailsWindows:
# Check if remote is runningInvoke-WebRequest -Uri "http://localhost:4201/remoteEntry.js" -UseBasicParsing
# Verify webpack configurationnpm run build -- --stats-error-detailsIssue 2: Shared dependency conflicts
# Check shared dependencies versionsnpm ls @angular/corenpm ls @angular/common
# Update webpack shared config if neededIssue 3: CORS issues in development
# Add to angular.json serve options:"serve": { "builder": "@angular-builders/custom-webpack:dev-server", "options": { "headers": { "Access-Control-Allow-Origin": "*" } }}π Step 7: Production Configuration
Section titled βπ Step 7: Production Configurationβ7.1 Production Webpack Config
Section titled β7.1 Production Webpack ConfigβCreate webpack.prod.config.js for production builds:
const ModuleFederationPlugin = require("@module-federation/webpack");
module.exports = { mode: "production", plugins: [ new ModuleFederationPlugin({ name: "host", filename: "remoteEntry.js",
remotes: { "mfeLoanCalculator": "https://loan-calculator.yourdomain.com/remoteEntry.js", "mfeUserDashboard": "https://user-dashboard.yourdomain.com/remoteEntry.js", "mfeTransactionHistory": "https://transaction-history.yourdomain.com/remoteEntry.js", },
shared: { "@angular/core": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/common": { singleton: true, strictVersion: true, requiredVersion: "auto" }, "@angular/router": { singleton: true, strictVersion: true, requiredVersion: "auto" }, }, }), ],};7.2 Environment-Based Configuration
Section titled β7.2 Environment-Based ConfigurationβUpdate mf.manifest.json structure:
{ "development": { "mfeLoanCalculator": "http://localhost:4201/remoteEntry.js", "mfeUserDashboard": "http://localhost:4202/remoteEntry.js", "mfeTransactionHistory": "http://localhost:4203/remoteEntry.js" }, "production": { "mfeLoanCalculator": "https://loan-calculator.yourdomain.com/remoteEntry.js", "mfeUserDashboard": "https://user-dashboard.yourdomain.com/remoteEntry.js", "mfeTransactionHistory": "https://transaction-history.yourdomain.com/remoteEntry.js" }}β Module Federation Setup Verification
Section titled ββ Module Federation Setup VerificationβChecklist
Section titled βChecklistβ- Module Federation installed in all applications
- Webpack configs created for host and remotes
- Remote modules properly exposed
- Host application configured to consume remotes
- Navigation working between MFEs
- Shared dependencies configured correctly
- RemoteEntry.js files accessible
- Dynamic routing implemented
- Production configuration prepared
- Testing script working
Expected File Structure
Section titled βExpected File StructureβProject Structure After Module Federation Setup:βββ host-banking-app/β βββ webpack.config.jsβ βββ webpack.prod.config.jsβ βββ src/assets/mf.manifest.jsonβ βββ updated angular.jsonβββ mfe-loan-calculator/β βββ webpack.config.jsβ βββ loan-calculator.module.tsβ βββ updated angular.jsonβββ mfe-user-dashboard/β βββ webpack.config.jsβ βββ user-dashboard.module.tsβ βββ updated angular.jsonβββ mfe-transaction-history/ βββ webpack.config.js βββ transaction-history.module.ts βββ updated angular.jsonπ Whatβs Next?
Section titled βπ Whatβs Next?βYour Module Federation setup is complete! Next steps:
- β Module Federation Setup Complete
- β‘οΈ Continue to: Host App Configuration - Enhance the host application
- π Alternative: Remote Configuration - Advanced remote setup
Your Angular MFEs can now communicate and share code at runtime! π