Micro Frontends: Scaling Frontend Development

Why Micro Frontends?

As frontend applications grow, they become difficult to maintain. Micro frontends allow teams to work independently, deploy separately, and use different technologies.

Module Federation (Webpack 5)

Host Application

// webpack.config.js (Host)
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        // Load remote micro frontends
        products: 'products@http://localhost:3001/remoteEntry.js',
        checkout: 'checkout@http://localhost:3002/remoteEntry.js',
        profile: 'profile@http://localhost:3003/remoteEntry.js'
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
      }
    })
  ]
};

Remote Application

// webpack.config.js (Products micro frontend)
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'products',
      filename: 'remoteEntry.js',
      exposes: {
        './ProductList': './src/components/ProductList',
        './ProductDetail': './src/components/ProductDetail'
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true }
      }
    })
  ]
};

Loading Remote Components

// In host application
import React, { Suspense, lazy } from 'react';

// Dynamic import of remote component
const ProductList = lazy(() => import('products/ProductList'));
const Checkout = lazy(() => import('checkout/CheckoutForm'));

function App() {
  return (
    
Loading products...
}> Loading checkout...}> ); }

Single-SPA Approach

// Root config
import { registerApplication, start } from 'single-spa';

registerApplication({
  name: '@myorg/navbar',
  app: () => System.import('@myorg/navbar'),
  activeWhen: () => true // Always active
});

registerApplication({
  name: '@myorg/products',
  app: () => System.import('@myorg/products'),
  activeWhen: (location) => location.pathname.startsWith('/products')
});

registerApplication({
  name: '@myorg/checkout',
  app: () => System.import('@myorg/checkout'),
  activeWhen: '/checkout'
});

start();
// Products micro frontend
import { registerApplication } from 'single-spa';
import singleSpaReact from 'single-spa-react';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const lifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: App,
  domElementGetter: () => document.getElementById('products-container')
});

export const { bootstrap, mount, unmount } = lifecycles;

Communication Between Micro Frontends

// Custom event bus
class EventBus {
  private events: Record = {};
  
  subscribe(event: string, callback: Function) {
    this.events[event] = this.events[event] || [];
    this.events[event].push(callback);
    
    return () => {
      this.events[event] = this.events[event].filter(cb => cb !== callback);
    };
  }
  
  publish(event: string, data: any) {
    (this.events[event] || []).forEach(callback => callback(data));
  }
}

// Expose globally
window.__EVENT_BUS__ = window.__EVENT_BUS__ || new EventBus();

// Usage in Products MFE
window.__EVENT_BUS__.publish('cart:add', { productId: '123', quantity: 1 });

// Usage in Cart MFE
window.__EVENT_BUS__.subscribe('cart:add', (item) => {
  addToCart(item);
});

Shared State

// Shared state using RxJS
import { BehaviorSubject } from 'rxjs';

interface User {
  id: string;
  name: string;
  email: string;
}

// Create shared store
const userSubject = new BehaviorSubject(null);

export const userStore = {
  getUser: () => userSubject.getValue(),
  setUser: (user: User) => userSubject.next(user),
  subscribe: (callback: (user: User | null) => void) => {
    const subscription = userSubject.subscribe(callback);
    return () => subscription.unsubscribe();
  }
};

// Expose as singleton
window.__USER_STORE__ = window.__USER_STORE__ || userStore;

Routing Coordination

// Shell router that delegates to micro frontends
function ShellRouter() {
  return (
    
      }>
          
        
      } />
      }>
          
        
      } />
      }>
          
        
      } />
    
  );
}

When to Use Micro Frontends

  • Large teams needing autonomy
  • Multiple products sharing components
  • Gradual migration from legacy systems
  • Different release cycles needed

Conclusion

Micro frontends solve organizational scaling, not technical problems. Use them when team independence and separate deployability justify the added complexity.

๐Ÿ“šTechnical Insights & Industry Trends

Insights & Knowledge Hub

Explore in-depth articles on software development, digital transformation, and emerging technologies. Learn from real-world experience.

Browse by Topic

๐Ÿ…ฐ๏ธ
ArchitectureJan 2024

Why Angular SSR Beats React for SEO in 2024

A comprehensive comparison of server-side rendering implementations and their impact on search engine optimization, performance, and user experience.

๐Ÿ”Œ
ArchitectureDec 2023

Microservices: When to Use and When to Avoid

Understanding the trade-offs of microservices architecture and making the right choice for your organization's scale, complexity, and team structure.

๐Ÿ—๏ธ
System ArchitectureJan 2024

Essential Design Patterns for Enterprise Systems

Master the fundamental design patterns that every software architect should know for building scalable, maintainable enterprise applications.

๐Ÿ—๏ธ
System ArchitectureJan 2024

Domain-Driven Design: A Practical Guide

Learn how to apply Domain-Driven Design principles to create software that truly reflects business requirements and scales with organizational complexity.

๐Ÿ—๏ธ
System ArchitectureDec 2023

Event-Driven Architecture: Complete Implementation Guide

Build loosely coupled, scalable systems using event-driven architecture patterns with practical examples using Kafka, RabbitMQ, and Azure Service Bus.

๐Ÿ—๏ธ
System ArchitectureDec 2023

RESTful API Design: Best Practices and Patterns

Design APIs that developers love to use. Learn REST principles, versioning strategies, error handling, and documentation best practices.

Deep Dives into Key Areas

๐Ÿ—๏ธ

System Architecture

Design patterns and architectural decisions

12 Articles
โ˜๏ธ

Cloud Computing

AWS, Azure, and cloud-native development

8 Articles
โšก

Performance

Optimization and scalability techniques

6 Articles
๐Ÿค–

AI & Machine Learning

Practical AI applications in enterprise

5 Articles
๐Ÿ”’

Security

Best practices and compliance

7 Articles
๐Ÿ“ฑ

Modern Frontend

Angular, React, and UI/UX best practices

10 Articles

Have a Project in Mind?

Let's turn your ideas into reality. Schedule a free consultation to discuss how we can help transform your business.