π By Bavithra Jagannatha Guptha
Senior Frontend Developer | Angular | Microfrontends | Accessibility Advocate
π Project Focus
As part of a large-scale modernization initiative, our team rebuilt a legacy System using a microfrontend architecture powered by Angular.
This approach enabled us to:
- Modularize the application
- Improve scalability
- Accelerate feature delivery
- Maintain high accessibility standards
ποΈ Project Context
β
Problem: Monolithic legacy app slowing development and deployment
β
Objective: Build a scalable, maintainable solution enabling team autonomy
β
Tech Stack: Angular, Webpack Module Federation, Azure DevOps, Docker
β οΈ Key Challenges
π Tight coupling in the legacy architecture
π Long deployment cycles
β Difficulty enabling parallel team contributions
π Performance issues with large datasets
π‘ Implementation Highlights
1. Defining Standard Contracts Between Microfrontends
A core concept in microfrontend architecture is the contract between microfrontends (MFEs). Each MFE must expose specific APIs, ensuring communication between them is smooth.
Hereβs an example of a shared contract for a ClaimsService that can be consumed by other MFEs:
// claims.service.ts - Shared Service in a Shared Library
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ClaimsService {
constructor(private http: HttpClient) {}
getClaimsData() {
return this.http.get('/api/claims');
}
submitClaim(claimData: any) {
return this.http.post('/api/submit-claim', claimData);
}
}
2. Shell Application Handling Routing and MFE Orchestration
In the shell application, we load the various MFEs dynamically. Webpack Module Federation allows us to expose and consume these MFEs in a modular way.
webpack.config.js in the Shell application:
javascript
Copy
Edit
module.exports = {
name: 'shell',
remotes: {
auth: 'auth@http://localhost:4201/remoteEntry.js',
dashboard: 'dashboard@http://localhost:4202/remoteEntry.js',
claimsForm: 'claimsForm@http://localhost:4203/remoteEntry.js',
claimsHistory: 'claimsHistory@http://localhost:4204/remoteEntry.js'
},
shared: {
angular: { singleton: true }
}
};
This setup allows us to load microfrontends like auth, dashboard, etc., from different ports at runtime.
Routing Setup in Shell Application (app-routing.module.ts):
const routes: Routes = [
{ path: '', loadChildren: () => import('dashboard/Module').then(m => m.DashboardModule) },
{ path: 'login', loadChildren: () => import('auth/Module').then(m => m.AuthModule) },
{ path: 'claims-form', loadChildren: () => import('claimsForm/Module').then(m => m.ClaimsFormModule) },
{ path: 'claims-history', loadChildren: () => import('claimsHistory/Module').then(m => m.ClaimsHistoryModule) }
];
This approach ensures that each MFE can independently handle its routing logic, while the shell application orchestrates them.
3. Implementing Full CI/CD Pipelines with Azure DevOps
We set up Azure DevOps pipelines to automate the build, test, and deployment processes. Hereβs an example of a simplified azure-pipelines.yml for the Shell application:
yaml
Copy
Edit
trigger:
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '16.x'
displayName: 'Install Node.js'
- task: Npm@1
inputs:
command: 'install'
displayName: 'Install Dependencies'
- task: Npm@1
inputs:
command: 'run build -- --prod'
displayName: 'Build Angular Project'
- task: AzureWebApp@1
inputs:
azureSubscription: 'Your-Azure-Subscription'
appName: 'your-web-app-name'
package: '$(Build.ArtifactStagingDirectory)/**/*.zip'
This YAML file sets up a pipeline that installs Node.js, builds the Angular project, and deploys it to Azure.
4. Docker for Deployment
Each microfrontend and the shell application are containerized using Docker. Below is an example Dockerfile for the shell application:
Dockerfile
Copy
Edit
# Use official node image as base
FROM node:16
# Set working directory
WORKDIR /app
# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install
# Copy the rest of the app code
COPY . .
# Expose the port
EXPOSE 4200
# Build the Angular app and serve
RUN npm run build --prod
CMD ["npx", "http-server", "dist"]
This Dockerfile builds the Angular app in production mode and serves it using http-server to run in a container.
π― Outcomes & Benefits
β
Faster deployments: Reduced from weeks to days
β
Decoupled development: Independent team workflows
β
Boosted performance: Faster load and response times
β
Improved UX/UI: Streamlined and accessible design
β
Simplified maintenance: Cleaner, modular codebase
π Final Thoughts
Adopting a microfrontend architecture allowed us to reimagine how large-scale applications can be built and maintained. The shift empowered teams to move faster, scale safely, and focus on user experience.
π¬ Have you adopted microfrontends in your project? Iβd love to hear your thoughts and lessons learned!
π If you'd like a code walkthrough or more technical insights, feel free to connect or message me.
Top comments (0)