Production-grade micro-frontend architecture demonstrating runtime integration of Angular and React applications using Webpack 5 Module Federation. This project showcases how different teams can work independently while seamlessly integrating their applications at runtime.
This isn't just another Todo app. This project demonstrates:
- β Cross-Framework Integration - Angular host consuming both React and Angular remotes
- β True Micro-Frontend Architecture - Independent development, deployment, and runtime integration
- β Component-Based Module Federation - Dynamic script loading without iframes
- β Bidirectional Communication - CustomEvents for cross-framework messaging
- β Web Components - Angular remotes exposed as custom elements using @angular/elements
- β Production-Ready Patterns - Error handling, CORS configuration, shared dependencies
graph TB
Host[Angular Host :4200]
ReactRemote[React Remote :3000]
AngularRemote[Angular Remote :61799]
Host -->|loads remoteEntry.js| ReactRemote
Host -->|loads remoteEntry.js| AngularRemote
ReactRemote -->|CustomEvent: reactToHost| Host
Host -->|CustomEvent: hostToReact| ReactRemote
AngularRemote -->|CustomEvent: angularRemoteToHost| Host
Host -->|CustomEvent: hostToAngularRemote| AngularRemote
style Host fill:#dd0031,stroke:#333,stroke-width:2px,color:#fff
style ReactRemote fill:#61dafb,stroke:#333,stroke-width:2px
style AngularRemote fill:#a6120d,stroke:#333,stroke-width:2px,color:#fff
π¦ module-federation/
βββ π angular-host/client/ # π’ Angular Host (Port 4200)
β βββ src/app/
β β βββ react-wrapper.component.ts # Loads React remote
β β βββ angular-wrapper.component.ts # Loads Angular remote
β β βββ home/home.component.ts # Side-by-side display
β βββ webpack.config.js # Webpack MF config
β
βββ π react/ # π΅ React Remote (Port 3000)
β βββ src/
β β βββ App.js # React remote component
β β βββ bootstrap.js # Module Federation bootstrap
β βββ webpack.config.js # Exposes React components
β
βββ π angular-remote/client/ # π΄ Angular Remote (Port 61799)
βββ src/app/
β βββ remote.component.ts # Remote component
β βββ remote-bootstrap.ts # Web Component bootstrap
β βββ remote-routing.module.ts # Route-based MF (optional)
βββ webpack.config.js # Exposes Angular components
| Application | Port | URL |
|---|---|---|
| π’ Angular Host | 4200 | http://localhost:4200 |
| π΅ React Remote | 3000 | http://localhost:3000 |
| π΄ Angular Remote | 61799 | http://localhost:61799 |
- Node.js 18+
- npm 9+
# Clone the repository
git clone https://github.com/Asafabekasis/Module-federation-setup-Angular-React.git
cd Module-federation-setup-Angular-React
# Install dependencies for all apps
cd angular-host/client && npm install && cd ../..
cd react && npm install && cd ../..
cd "angular-remote/client" && npm install && cd ../..
# Start all applications (requires 3 terminals)
# Terminal 1 - Angular Host (Port 4200)
cd angular-host/client
ng serve
# Running at http://localhost:4200
# Terminal 2 - React Remote (Port 3000)
cd react
npm start
# Running at http://localhost:3000
# Terminal 3 - Angular Remote (Port 61799)
cd "angular-remote/client"
ng serve
# Running at http://localhost:61799
# Open http://localhost:4200 in your browser to view the host application# Install concurrently globally
npm install -g concurrently
# Run all apps at once (from root)
concurrently "cd angular-host/client && ng serve" "cd react && npm start" "cd 'angular-remote/client' && ng serve"Each remote is loaded at runtime via remoteEntry.js, allowing independent deployments:
// React Remote - Dynamic Script Loading
const script = document.createElement('script');
script.src = 'http://localhost:3000/remoteEntry.js';
document.head.appendChild(script);
// Access exposed module
const container = window.reactApp;
const factory = await container.get('./App');
const ReactComponent = factory();CustomEvents enable seamless messaging between Angular and React:
// Host β React
window.dispatchEvent(new CustomEvent('hostToReact', {
detail: message
}));
// React β Host
window.addEventListener('reactToHost', (event) => {
console.log(event.detail);
});Angular remotes use @angular/elements to expose components as web components:
import { createCustomElement } from '@angular/elements';
const RemoteElement = createCustomElement(RemoteComponent, {
injector: app.injector
});
customElements.define('app-remote-element', RemoteElement);// webpack.config.js
shared: {
"@angular/core": { singleton: true, strictVersion: false },
"react": { singleton: true },
"react-dom": { singleton: true }
}Both React and Angular remotes displayed simultaneously with bidirectional communication
Key Features Shown:
- π΅ React Remote (Port 3000) - Left side with cyan styling
- π΄ Angular Remote (Port 61799) - Right side with purple styling
- π¨ Message inputs for sending data to each remote
- π¬ Real-time message display from remotes to host
- π Bidirectional communication via CustomEvents
Full-page remote via /angular-children route
React Remote (webpack.config.js)
new ModuleFederationPlugin({
name: "reactApp",
filename: "remoteEntry.js",
exposes: {
'./App': './src/App',
'./react': 'react',
'./react-dom/client': 'react-dom/client'
}
})Angular Remote (webpack.config.js)
new ModuleFederationPlugin({
name: "angularRemote",
filename: "remoteEntry.js",
exposes: {
'./RemoteComponent': './src/app/remote-bootstrap.ts',
'./RemoteModule': './src/app/remote-routing.module.ts'
}
})try {
const factory = await container.get('./App');
// Load component
} catch (error) {
// Display fallback UI
this.container.nativeElement.innerHTML = `
<div class="error-message">
β οΈ Remote Not Available
</div>
`;
}// Dynamic origin-based CORS headers
devServer: {
setupMiddlewares: (middlewares, devServer) => {
devServer.app.use((req, res, next) => {
const origin = req.headers.origin;
const allowedOrigins = ['http://localhost:4200', ...];
if (origin && allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
next();
});
return middlewares;
}
}This architecture is ideal for:
- Enterprise Portals - Multiple teams contributing widgets/sections
- Gradual Migration - Migrating from Angular to React (or vice versa) incrementally
- Multi-Team Development - Independent development and deployment cycles
- Plugin Systems - Third-party integrations displayed together
- Dashboard Applications - Multiple data sources in unified view
| Technology | Version | Purpose |
|---|---|---|
| Angular | 19.2.x | Host application & Remote |
| React | 18.2.x | Remote application |
| Webpack | 5.x | Module Federation |
| TypeScript | 5.x | Type safety |
| @angular/elements | 19.x | Web Components |
| @angular-architects/module-federation | 20.x | MF helpers |
| Route | Description | Type |
|---|---|---|
/ |
Home - Both remotes side-by-side | Component-based |
/react |
React remote full page | Component-based |
/angular |
Angular remote full page | Component-based |
/angular-children |
Angular remote via loadChildren | Route-based |
// environment.prod.ts
export const environment = {
production: true,
remotes: {
react: 'https://react-remote.yourcdn.com/remoteEntry.js',
angular: 'https://angular-remote.yourcdn.com/remoteEntry.js'
}
};# Build all applications
cd angular-host/client && ng build --configuration production
cd react && npm run build
cd "angular-remote/client" && ng build --configuration production- Deploy each remote independently to CDN/hosting
- Update remote URLs in host environment config
- Deploy host application
- Zero-downtime updates - deploy remotes without redeploying host
# Run unit tests
cd angular-host/client && ng test
cd react && npm test
# Run e2e tests (if configured)
cd angular-host/client && ng e2eContributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE file for details
Asaf Abekasis
- GitHub: @Asafabekasis
- LinkedIn: [https://linkedin.com/in/asaf-abekasis]
- Webpack Module Federation documentation
- @angular-architects/module-federation team
- React and Angular communities
β If you find this project helpful, please consider giving it a star! β
