Angular MFE Documentation & Advanced Concepts | Complete Guide
This final guide covers advanced Micro Frontend concepts, best practices, and strategies for creating comprehensive documentation for your Angular MFE platform.
📚 Documentation Strategy
Section titled “📚 Documentation Strategy”Documentation Types
Section titled “Documentation Types”- Technical Documentation: API references, architecture diagrams
- User Guides: End-user tutorials and workflows
- Developer Documentation: Setup guides, contribution guidelines
- Architecture Documentation: System design and patterns
- Deployment Guides: Infrastructure and deployment processes
Documentation Structure
Section titled “Documentation Structure”Documentation Architecture:├── README.md (Overview)├── docs/│ ├── architecture/│ │ ├── overview.md│ │ ├── mfe-patterns.md│ │ └── security.md│ ├── development/│ │ ├── getting-started.md│ │ ├── local-setup.md│ │ └── testing.md│ ├── deployment/│ │ ├── azure-setup.md│ │ └── ci-cd.md│ ├── api/│ │ └── mfe-interfaces.md│ └── troubleshooting/│ └── common-issues.md└── examples/ ├── loan-calculator/ ├── user-dashboard/ └── transaction-history/
🏗️ Advanced Architecture Patterns
Section titled “🏗️ Advanced Architecture Patterns”1. Micro Frontend Communication Patterns
Section titled “1. Micro Frontend Communication Patterns”Event-Driven Communication
Section titled “Event-Driven Communication”shared-event-bus.service.ts:
import { Injectable } from '@angular/core';import { Subject, Observable } from 'rxjs';import { filter, map } from 'rxjs/operators';
export interface MfeEvent { type: string; source: string; payload: any; timestamp: Date;}
@Injectable({ providedIn: 'root'})export class SharedEventBusService { private eventSubject = new Subject<MfeEvent>();
// Emit event to all MFEs emit(type: string, payload: any, source: string): void { const event: MfeEvent = { type, source, payload, timestamp: new Date() };
this.eventSubject.next(event); }
// Listen for specific event types on(eventType: string): Observable<MfeEvent> { return this.eventSubject.asObservable().pipe( filter(event => event.type === eventType) ); }
// Listen for events from specific MFE fromSource(source: string): Observable<MfeEvent> { return this.eventSubject.asObservable().pipe( filter(event => event.source === source) ); }}
Shared State Management
Section titled “Shared State Management”shared-state.service.ts:
import { Injectable } from '@angular/core';import { BehaviorSubject, Observable } from 'rxjs';
export interface SharedState { user: any; theme: 'light' | 'dark'; language: string; notifications: any[];}
@Injectable({ providedIn: 'root'})export class SharedStateService { private stateSubject = new BehaviorSubject<SharedState>({ user: null, theme: 'light', language: 'en', notifications: [] });
public state$ = this.stateSubject.asObservable();
updateUser(user: any): void { const currentState = this.stateSubject.value; this.stateSubject.next({ ...currentState, user }); }
updateTheme(theme: 'light' | 'dark'): void { const currentState = this.stateSubject.value; this.stateSubject.next({ ...currentState, theme });
// Apply theme globally document.documentElement.setAttribute('data-theme', theme); }
addNotification(notification: any): void { const currentState = this.stateSubject.value; this.stateSubject.next({ ...currentState, notifications: [...currentState.notifications, notification] }); }
getState(): SharedState { return this.stateSubject.value; }}
2. Advanced Module Federation Patterns
Section titled “2. Advanced Module Federation Patterns”Dynamic MFE Registration
Section titled “Dynamic MFE Registration”dynamic-mfe-loader.service.ts:
import { Injectable, Injector, ComponentRef, ViewContainerRef } from '@angular/core';import { loadRemoteModule } from '@angular-architects/module-federation';
export interface MfeConfig { name: string; remoteEntry: string; exposedModule: string; componentName: string; displayName: string; version: string; permissions: string[];}
@Injectable({ providedIn: 'root'})export class DynamicMfeLoaderService { private loadedMfes = new Map<string, any>(); private mfeConfigs = new Map<string, MfeConfig>();
constructor(private injector: Injector) {}
async registerMfe(config: MfeConfig): Promise<void> { this.mfeConfigs.set(config.name, config);
try { const module = await loadRemoteModule({ type: 'module', remoteEntry: config.remoteEntry, exposedModule: config.exposedModule });
this.loadedMfes.set(config.name, module); console.log(`✅ MFE ${config.name} registered successfully`); } catch (error) { console.error(`❌ Failed to register MFE ${config.name}:`, error); } }
async loadComponent( mfeName: string, container: ViewContainerRef ): Promise<ComponentRef<any> | null> { const module = this.loadedMfes.get(mfeName); const config = this.mfeConfigs.get(mfeName);
if (!module || !config) { console.error(`MFE ${mfeName} not found or not registered`); return null; }
try { const component = module[config.componentName]; const componentRef = container.createComponent(component); return componentRef; } catch (error) { console.error(`Failed to load component from MFE ${mfeName}:`, error); return null; } }
getMfeConfig(name: string): MfeConfig | undefined { return this.mfeConfigs.get(name); }
getAvailableMfes(): MfeConfig[] { return Array.from(this.mfeConfigs.values()); }}
3. Error Boundaries and Fallbacks
Section titled “3. Error Boundaries and Fallbacks”MFE Error Boundary
Section titled “MFE Error Boundary”mfe-error-boundary.component.ts:
import { Component, Input, OnInit, ErrorHandler, ViewChild, ViewContainerRef } from '@angular/core';import { DynamicMfeLoaderService } from '../services/dynamic-mfe-loader.service';
@Component({ selector: 'app-mfe-error-boundary', template: ` <div class="mfe-container"> <div *ngIf="!hasError" #mfeContainer></div>
<div *ngIf="hasError" class="mfe-error-fallback"> <div class="error-content"> <h3>⚠️ Unable to Load {{ mfeName }}</h3> <p>{{ errorMessage }}</p> <div class="error-actions"> <button class="btn btn-primary" (click)="retry()"> 🔄 Retry </button> <button class="btn btn-secondary" (click)="showFallback()"> 📄 Show Alternative </button> </div> </div> </div>
<div *ngIf="showingFallback" class="mfe-fallback"> <ng-content select="[slot=fallback]"></ng-content> </div> </div> `, styles: [` .mfe-error-fallback { padding: 2rem; text-align: center; background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; margin: 1rem 0; }
.error-content h3 { color: #dc3545; margin-bottom: 1rem; }
.error-actions { margin-top: 1rem; display: flex; gap: 1rem; justify-content: center; }
.btn { padding: 0.5rem 1rem; border: none; border-radius: 4px; cursor: pointer; font-weight: 600; }
.btn-primary { background: #007bff; color: white; }
.btn-secondary { background: #6c757d; color: white; } `]})export class MfeErrorBoundaryComponent implements OnInit { @Input() mfeName!: string; @Input() maxRetries = 3; @ViewChild('mfeContainer', { read: ViewContainerRef }) container!: ViewContainerRef;
hasError = false; showingFallback = false; errorMessage = ''; retryCount = 0;
constructor( private mfeLoader: DynamicMfeLoaderService, private errorHandler: ErrorHandler ) {}
async ngOnInit() { await this.loadMfe(); }
private async loadMfe(): Promise<void> { try { this.hasError = false; this.showingFallback = false;
const componentRef = await this.mfeLoader.loadComponent( this.mfeName, this.container );
if (!componentRef) { throw new Error(`Failed to load MFE: ${this.mfeName}`); } } catch (error) { this.handleError(error); } }
private handleError(error: any): void { this.hasError = true; this.errorMessage = error.message || 'Unknown error occurred';
console.error(`MFE ${this.mfeName} failed to load:`, error); this.errorHandler.handleError(error); }
async retry(): Promise<void> { if (this.retryCount < this.maxRetries) { this.retryCount++; await this.loadMfe(); } else { this.errorMessage = `Maximum retry attempts (${this.maxRetries}) exceeded`; } }
showFallback(): void { this.showingFallback = true; this.hasError = false; }}
🔒 Security Best Practices
Section titled “🔒 Security Best Practices”1. Content Security Policy Implementation
Section titled “1. Content Security Policy Implementation”security.service.ts:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root'})export class SecurityService { private trustedDomains: string[] = [ 'https://banking.yourdomain.com', 'https://loan-calculator.yourdomain.com', 'https://user-dashboard.yourdomain.com', 'https://transactions.yourdomain.com' ];
validateMfeSource(url: string): boolean { try { const urlObj = new URL(url); return this.trustedDomains.some(domain => urlObj.origin === new URL(domain).origin ); } catch { return false; } }
sanitizeData(data: any): any { // Implement data sanitization logic if (typeof data === 'string') { return this.sanitizeString(data); }
if (Array.isArray(data)) { return data.map(item => this.sanitizeData(item)); }
if (typeof data === 'object' && data !== null) { const sanitized: any = {}; for (const [key, value] of Object.entries(data)) { sanitized[this.sanitizeString(key)] = this.sanitizeData(value); } return sanitized; }
return data; }
private sanitizeString(input: string): string { return input .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') .replace(/javascript:/gi, '') .replace(/on\w+\s*=/gi, ''); }}
2. Authentication & Authorization
Section titled “2. Authentication & Authorization”mfe-auth.guard.ts:
import { Injectable } from '@angular/core';import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';import { Observable } from 'rxjs';import { AuthService } from './auth.service';
@Injectable({ providedIn: 'root'})export class MfeAuthGuard implements CanActivate {
constructor(private authService: AuthService) {}
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> | Promise<boolean> | boolean {
const requiredPermissions = route.data['permissions'] as string[]; const mfeName = route.data['mfeName'] as string;
if (!this.authService.isAuthenticated) { console.warn(`Access denied to MFE ${mfeName}: User not authenticated`); return false; }
if (requiredPermissions && requiredPermissions.length > 0) { const hasPermission = this.authService.hasPermissions(requiredPermissions);
if (!hasPermission) { console.warn(`Access denied to MFE ${mfeName}: Insufficient permissions`); return false; } }
return true; }}
📊 Performance Optimization Patterns
Section titled “📊 Performance Optimization Patterns”1. Lazy Loading with Preloading
Section titled “1. Lazy Loading with Preloading”smart-preload.strategy.ts:
import { Injectable } from '@angular/core';import { PreloadingStrategy, Route } from '@angular/router';import { Observable, of, timer } from 'rxjs';import { switchMap } from 'rxjs/operators';
@Injectable({ providedIn: 'root'})export class SmartPreloadStrategy implements PreloadingStrategy {
preload(route: Route, fn: () => Observable<any>): Observable<any> { const connection = (navigator as any).connection;
// Don't preload on slow connections if (connection && connection.effectiveType === '2g') { return of(null); }
// Preload after a delay for non-critical routes const delay = route.data?.['preloadDelay'] || 2000; const priority = route.data?.['priority'] || 'low';
if (priority === 'high') { return fn(); }
return timer(delay).pipe( switchMap(() => fn()) ); }}
2. Bundle Optimization
Section titled “2. Bundle Optimization”bundle-analyzer.js:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = { plugins: [ new BundleAnalyzerPlugin({ analyzerMode: 'static', reportFilename: 'bundle-report.html', openAnalyzer: false, generateStatsFile: true, statsFilename: 'bundle-stats.json' }) ], optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all', priority: 10 }, common: { name: 'common', minChunks: 2, chunks: 'all', priority: 5, reuseExistingChunk: true } } } }};
📝 Comprehensive Documentation Template
Section titled “📝 Comprehensive Documentation Template”README.md Template
Section titled “README.md Template”# 🏦 Banking Platform - Micro Frontend Architecture
> Modern, scalable banking platform built with Angular Micro Frontends
[](https://github.com/yourusername/banking-platform/actions)[](https://banking.yourdomain.com)[](https://opensource.org/licenses/MIT)
## 🚀 Quick Start
```bash# Clone and start all MFEsgit clone https://github.com/yourusername/banking-platform.gitcd banking-platform./start-all-dev.sh
Visit http://localhost:4200 to see the application.
🏗️ Architecture
Section titled “🏗️ Architecture”This project demonstrates a production-ready Micro Frontend architecture with:
- Host Application: Main shell and navigation
- Loan Calculator MFE: Mortgage and loan calculations
- User Dashboard MFE: Account overview and management
- Transaction History MFE: Financial transaction tracking
Technology Stack
Section titled “Technology Stack”Technology | Purpose | Version |
---|---|---|
Angular | Frontend Framework | 17+ |
Module Federation | Runtime Integration | Webpack 5 |
Azure Static Web Apps | Hosting & Deployment | Latest |
TypeScript | Type Safety | 5.0+ |
SCSS | Styling | Latest |
📂 Project Structure
Section titled “📂 Project Structure”banking-platform/├── host-banking-app/ # Main shell application├── mfe-loan-calculator/ # Loan calculator MFE├── mfe-user-dashboard/ # User dashboard MFE├── mfe-transaction-history/ # Transaction history MFE├── docs/ # Documentation├── scripts/ # Development scripts└── .github/workflows/ # CI/CD pipelines
🔧 Development
Section titled “🔧 Development”Prerequisites
Section titled “Prerequisites”- Node.js 18+
- Angular CLI 17+
- Git
Local Development
Section titled “Local Development”-
Start all applications:
Terminal window npm run start:all -
Start individual MFE:
Terminal window cd mfe-loan-calculatornpm start -
Run tests:
Terminal window npm run test:all
Building for Production
Section titled “Building for Production”npm run build:all
🚀 Deployment
Section titled “🚀 Deployment”This project is configured for Azure Static Web Apps with GitHub Actions:
- Automatic deployment on push to
main
branch - Preview deployments for pull requests
- Custom domains with SSL certificates
- Global CDN distribution
See Deployment Guide for detailed instructions.
📊 Performance
Section titled “📊 Performance”Current performance metrics:
- First Load: < 2 seconds
- MFE Load Time: < 1 second
- Bundle Size: < 500KB total
- Lighthouse Score: 95+
🔒 Security
Section titled “🔒 Security”- Content Security Policy (CSP) implemented
- HTTPS enforced
- Authentication with Azure AD B2C
- Input sanitization and validation
🤝 Contributing
Section titled “🤝 Contributing”- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Commit changes:
git commit -m 'Add amazing feature'
- Push to branch:
git push origin feature/amazing-feature
- Open a Pull Request
See Contributing Guide for detailed guidelines.
📖 Documentation
Section titled “📖 Documentation”📄 License
Section titled “📄 License”This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
Section titled “🙏 Acknowledgments”- Angular team for the amazing framework
- Module Federation community
- Azure Static Web Apps team
📞 Support
Section titled “📞 Support”- 📧 Email: support@yourdomain.com
- 💬 Discussions: GitHub Discussions
- 🐛 Issues: GitHub Issues
Made with ❤️ by Your Name
---
## 🎯 Blog Post Template
### **"Building Production-Ready Micro Frontends with Angular"**
```markdown# Building Production-Ready Micro Frontends with Angular: A Complete Guide
## Introduction
Micro Frontends represent a paradigm shift in frontend architecture, extending the microservices concept to the frontend. In this comprehensive guide, I'll walk you through building a production-ready banking platform using Angular and Module Federation.
## The Challenge
Traditional monolithic frontends become unwieldy as teams and applications grow. We needed:
- **Team Independence**: Multiple teams working without conflicts- **Technology Flexibility**: Different Angular versions per team- **Independent Deployment**: Deploy features without full application rebuilds- **Scalability**: Handle increasing complexity and team size
## Our Solution: Angular Micro Frontends
We chose Angular with Module Federation for several reasons:
### Why Angular?- Mature ecosystem and tooling- Strong TypeScript integration- Excellent performance optimization- Enterprise-ready features
### Why Module Federation?- Runtime code sharing- Independent deployment- Shared dependency optimization- Proven at scale
## Architecture Overview
Our banking platform consists of:
1. **Host Application**: Navigation, authentication, layout2. **Loan Calculator MFE**: Mortgage calculations and tools3. **User Dashboard MFE**: Account overview and management4. **Transaction History MFE**: Financial transaction tracking
[Include architecture diagram]
## Implementation Highlights
### 1. Module Federation Configuration
The key to our setup is the webpack configuration:
```javascript// Host application webpack.config.jsconst ModuleFederationPlugin = require("@module-federation/webpack");
module.exports = { plugins: [ new ModuleFederationPlugin({ name: "host", remotes: { "loanCalculator": "https://loan-calculator.yourdomain.com/remoteEntry.js", "userDashboard": "https://dashboard.yourdomain.com/remoteEntry.js" }, shared: { "@angular/core": { singleton: true }, "@angular/common": { singleton: true } } }) ]};
2. Dynamic Loading Strategy
Section titled “2. Dynamic Loading Strategy”We implemented dynamic MFE loading with error boundaries:
async loadMfe(mfeName: string) { try { const module = await loadRemoteModule({ remoteEntry: this.getMfeUrl(mfeName), exposedModule: './Module' }); return module; } catch (error) { this.showFallback(mfeName); this.logError(error); }}
3. Shared State Management
Section titled “3. Shared State Management”Cross-MFE communication uses an event bus pattern:
// Emit events between MFEsthis.eventBus.emit('user-updated', { userId: 123 });
// Listen for eventsthis.eventBus.on('user-updated').subscribe(event => { this.updateUserDisplay(event.payload);});
Deployment Strategy
Section titled “Deployment Strategy”We use Azure Static Web Apps with GitHub Actions:
- Individual MFE Deployment: Each MFE deploys independently
- Host Configuration Update: Dynamic manifest for MFE URLs
- Rollback Capability: Independent rollback per MFE
- Blue-Green Deployment: Zero-downtime deployments
Performance Results
Section titled “Performance Results”After optimization, we achieved:
- First Load: 1.8 seconds (down from 4.2s)
- MFE Load Time: 0.6 seconds average
- Bundle Size: 420KB total (down from 1.2MB)
- Lighthouse Score: 96/100
Lessons Learned
Section titled “Lessons Learned”What Worked Well
Section titled “What Worked Well”- Module Federation reliability
- Team independence and velocity
- Deployment flexibility
- Performance improvements
Challenges Faced
Section titled “Challenges Faced”- Initial learning curve
- Debugging complexity
- Shared dependency management
- Testing strategy evolution
Best Practices
Section titled “Best Practices”- Start Simple: Begin with clear MFE boundaries
- Shared Dependencies: Carefully manage shared libraries
- Error Handling: Implement robust fallback mechanisms
- Testing Strategy: Multi-level testing approach
- Monitoring: Comprehensive observability setup
Future Enhancements
Section titled “Future Enhancements”- Server-Side Rendering (SSR) support
- Advanced caching strategies
- Enhanced security patterns
- GraphQL federation integration
Conclusion
Section titled “Conclusion”Micro Frontends with Angular and Module Federation enabled our team to:
- Scale Development: 3 teams working independently
- Improve Performance: 50% faster load times
- Increase Deployment Frequency: Daily deployments vs. monthly
- Enhance User Experience: Better perceived performance
The investment in Micro Frontend architecture pays dividends in team productivity and application maintainability.
Resources
Section titled “Resources”Have questions about Micro Frontends? Contact me or follow me on Twitter
---
## ✅ Documentation & Advanced Concepts Checklist
### **Documentation Complete**
- [ ] **Architecture documentation** with diagrams and patterns- [ ] **API documentation** for all MFE interfaces- [ ] **Development guides** for setup and contribution- [ ] **Deployment documentation** for Azure and CI/CD- [ ] **Troubleshooting guides** for common issues- [ ] **Performance benchmarks** and optimization tips- [ ] **Security guidelines** and best practices- [ ] **Blog post** for sharing experience- [ ] **Video tutorials** (optional)- [ ] **Community resources** and support channels
### **Advanced Patterns Implemented**
- [ ] **Event-driven communication** between MFEs- [ ] **Shared state management** across boundaries- [ ] **Dynamic MFE registration** and loading- [ ] **Error boundaries** with fallback mechanisms- [ ] **Smart preloading** strategies- [ ] **Security validation** for MFE sources- [ ] **Performance monitoring** and analytics- [ ] **Bundle optimization** and splitting
---
## 🎉 Congratulations!
You've completed the comprehensive Angular Micro Frontend tutorial series! You now have:
- ✅ **Complete MFE Platform**: Production-ready banking application- ✅ **Advanced Patterns**: Error handling, communication, security- ✅ **Production Deployment**: Azure Static Web Apps with CI/CD- ✅ **Comprehensive Documentation**: Guides, APIs, and tutorials- ✅ **Performance Optimization**: Fast loading and efficient bundling- ✅ **Best Practices**: Security, testing, and maintainability
## 🚀 What's Next?
1. **Share Your Experience**: Write blog posts and create tutorials2. **Contribute to Community**: Share patterns and solutions3. **Explore Advanced Topics**: SSR, GraphQL federation, advanced caching4. **Scale Your Implementation**: Add more MFEs and teams5. **Monitor and Optimize**: Continuous improvement and performance tuning
Your Angular Micro Frontend journey is just beginning! 🎯