DEV Community

Cover image for Building Micro-Frontends with Module Federation: A Complete Implementation Guide
Aarav Joshi
Aarav Joshi

Posted on

Building Micro-Frontends with Module Federation: A Complete Implementation Guide

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

Modern web development has evolved significantly to address the growing complexity of frontend applications. Micro-frontend architecture presents a practical solution for building scalable, maintainable applications by breaking down monolithic frontends into smaller, independent units.

Module Federation represents a powerful approach to micro-frontends. This architecture, introduced in Webpack 5, enables real-time code sharing between applications:

// Host application
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      filename: 'remoteEntry.js',
      remotes: {
        app1: 'app1@http://localhost:3001/remoteEntry.js',
        app2: 'app2@http://localhost:3002/remoteEntry.js'
      },
      shared: ['react', 'react-dom']
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ]
};
Enter fullscreen mode Exit fullscreen mode

Web Components provide a standardized way to create reusable, framework-agnostic components. This approach enables true technology independence:

class MicroFrontend extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'open' });
  }

  static get observedAttributes() {
    return ['name', 'url'];
  }

  async connectedCallback() {
    const content = await this.loadContent();
    this.shadow.innerHTML = content;
  }

  async loadContent() {
    const response = await fetch(this.getAttribute('url'));
    return response.text();
  }
}

customElements.define('micro-frontend', MicroFrontend);
Enter fullscreen mode Exit fullscreen mode

iFrame-based integration offers strong isolation between different parts of the application. We implement this using a simple coordinator:

class FrameManager {
  constructor(container) {
    this.container = container;
    this.frames = new Map();
  }

  loadMicroFrontend(name, url) {
    const frame = document.createElement('iframe');
    frame.src = url;
    frame.style.border = 'none';
    frame.style.width = '100%';
    frame.style.height = '100%';

    this.frames.set(name, frame);
    this.container.appendChild(frame);
  }

  removeMicroFrontend(name) {
    const frame = this.frames.get(name);
    if (frame) {
      frame.remove();
      this.frames.delete(name);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Client-side composition requires a shell application to manage routing and micro-frontend integration:

class Shell {
  constructor() {
    this.routes = new Map();
    this.currentMicroFrontend = null;
  }

  registerRoute(path, microFrontendConfig) {
    this.routes.set(path, microFrontendConfig);
  }

  async handleNavigation(path) {
    const config = this.routes.get(path);
    if (!config) return;

    if (this.currentMicroFrontend) {
      await this.currentMicroFrontend.unmount();
    }

    const module = await System.import(config.url);
    this.currentMicroFrontend = await module.mount(config.container);
  }
}
Enter fullscreen mode Exit fullscreen mode

Server-side composition implements micro-frontend assembly before sending to the client:

const express = require('express');
const axios = require('axios');

class ServerComposition {
  async composePage(req, res) {
    try {
      const [header, content, footer] = await Promise.all([
        axios.get('http://header-service/fragment'),
        axios.get('http://content-service/fragment'),
        axios.get('http://footer-service/fragment')
      ]);

      const html = `
        <!DOCTYPE html>
        <html>
          <body>
            ${header.data}
            ${content.data}
            ${footer.data}
          </body>
        </html>
      `;

      res.send(html);
    } catch (error) {
      res.status(500).send('Composition failed');
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Asset sharing requires careful coordination of shared resources:

// shared-config.js
module.exports = {
  design: {
    colors: {
      primary: '#007bff',
      secondary: '#6c757d'
    },
    typography: {
      fontFamily: 'Arial, sans-serif',
      fontSize: '16px'
    }
  },
  utils: {
    formatDate: (date) => new Intl.DateTimeFormat().format(date),
    formatCurrency: (amount) => new Intl.NumberFormat().format(amount)
  }
};
Enter fullscreen mode Exit fullscreen mode

Each architecture brings specific benefits and challenges. Module Federation excels in development efficiency but requires careful dependency management. Web Components offer excellent isolation but may need additional work for cross-browser compatibility. iFrames provide the strongest isolation but can impact performance and user experience.

Client-side composition offers flexibility but increases browser load. Server-side composition improves initial load times but requires more complex server infrastructure. Asset sharing maintains consistency but needs careful version management.

I recommend starting with Module Federation for most applications, as it provides a good balance of flexibility and complexity. However, the choice depends on specific requirements, team structure, and technical constraints.

The success of micro-frontend implementation relies on clear team boundaries, well-defined interfaces, and robust deployment processes. Regular evaluation and adjustment of the chosen architecture ensure long-term sustainability and scalability.

Monitoring and performance optimization become crucial with micro-frontends. Implement comprehensive monitoring:

class PerformanceMonitor {
  constructor() {
    this.metrics = {};
  }

  measure(name, startTime) {
    const duration = performance.now() - startTime;
    this.metrics[name] = duration;
  }

  report() {
    console.table(this.metrics);
  }
}
Enter fullscreen mode Exit fullscreen mode

These architectural patterns continue to evolve with web technologies. Regular assessment of new tools and approaches helps maintain modern, efficient applications while addressing growing complexity in frontend development.


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)