0Pricing

Unlocking Scalability: A Beginner's Guide to Micro Frontends with Module Federation

Dive into the world of Micro Frontends and learn how Webpack 5's Module Federation empowers you to build scalable, independently deployable, and technologically agnostic web applications. This introductory guide covers the 'what' and 'why' of this revolutionary architecture.

M
Micro Frontends Architecture with Module Federation · 8 min read · 1,575 words

Welcome to the first installment of our deep dive into Micro Frontends Architecture with Module Federation! At CoddyKit, we believe in empowering developers with the knowledge to build modern, robust, and scalable applications. Today, we're embarking on a journey to understand one of the most exciting paradigms in frontend development: Micro Frontends, supercharged by Webpack 5's Module Federation.

If you've ever wrestled with a massive, monolithic frontend codebase – slow build times, complex deployments, team bottlenecks, and the sheer difficulty of upgrading a core framework – then you already understand the pain points Micro Frontends aim to solve. Think of it as bringing the agility and independence of microservices to your user interface layer.

The Monolith Conundrum: Why We Need a Change

For years, the standard approach to building web applications involved creating a single, cohesive frontend application. This "monolith" often starts small but grows into a behemoth, leading to several challenges:

  • Slow Development Cycles: A single codebase means more merge conflicts, slower builds, and a higher cognitive load for developers.
  • Team Bottlenecks: Multiple teams often work on different features within the same codebase, leading to dependencies and coordination overhead.
  • Technology Lock-in: Upgrading a major framework (like React to a newer version, or even switching to Vue) becomes an enormous, risky undertaking.
  • High-Risk Deployments: A small change in one part of the application can potentially break another, requiring extensive regression testing for every release.
  • Scaling Challenges: It's hard to scale development teams efficiently when everyone is working on the same large codebase.

Introducing Micro Frontends: Deconstructing the UI

Inspired by the success of microservices in backend development, Micro Frontends propose breaking down a single frontend application into smaller, autonomous applications. Each micro frontend:

  • Is developed, tested, and deployed independently.
  • Can be owned by a dedicated, cross-functional team.
  • Can potentially use its own technology stack (e.g., one team uses React, another Vue).
  • Integrates seamlessly at runtime to form a cohesive user experience.

Imagine an e-commerce platform. Instead of one massive app, you could have a "Product Listing" micro frontend, a "Shopping Cart" micro frontend, a "User Profile" micro frontend, and so on. Each part functions independently but comes together under a main "shell" application.

The Orchestration Challenge: How Do They Come Together?

While the concept of independent frontend pieces is appealing, the practical challenge has always been how to effectively combine them into a single, seamless user experience without introducing new complexities. Early approaches included:

  • Iframes: Simple but come with significant limitations regarding communication, routing, and shared context.
  • Web Components: Excellent for encapsulating UI, but require careful management for cross-framework compatibility and dependency sharing.
  • Build-time Integration: Publishing components as packages and consuming them, which often reintroduces monolithic build issues.

These methods often struggled with dependency management, bundle size optimization, and true runtime independence. This is where Module Federation steps in as a game-changer.

Enter Module Federation: The True Game Changer

Webpack 5 introduced a revolutionary feature called Module Federation, which provides a robust and elegant solution for implementing Micro Frontends. It allows multiple Webpack builds to expose and consume modules from each other at runtime. This isn't just about sharing code – it's about sharing entire applications or parts of applications dynamically.

How Module Federation Works at a High Level

Module Federation operates on two core concepts:

  1. Host Application: This is the main shell application that consumes modules (micro frontends) from other applications.
  2. Remote Application: This is the micro frontend application that exposes modules to be consumed by other applications (hosts).

The magic happens in your webpack.config.js. You configure your application to either expose certain modules (making them available to others) or to consume modules from remote applications. Webpack handles the heavy lifting of loading these modules dynamically, resolving dependencies, and even sharing common libraries to avoid duplication.

Key Advantages of Module Federation for Micro Frontends:

  • True Runtime Integration: Modules are loaded and integrated at runtime, not build time, offering unparalleled flexibility.
  • Shared Dependencies: Module Federation can intelligently share common libraries (like React or Vue) between host and remote applications, drastically reducing bundle sizes and improving performance.
  • Technology Agnostic: While primarily a Webpack feature, it enables applications built with different frameworks (React, Vue, Angular, Svelte) to coexist and interact seamlessly, as long as they compile down to JavaScript.
  • Simplified Deployment: Each micro frontend can be deployed independently, without requiring a redeployment of the entire application.
  • Improved Performance: By sharing dependencies and lazy loading remotes, overall application performance can be significantly enhanced.

Getting Started: A Simple "Hello World" Example

Let's illustrate with a conceptual example. Imagine we want to build a simple application where a "Host" app loads a "Greeting" component from a "Remote" app.

1. The Remote Application (remote-app)

This app exposes a simple Greeting component.

remote-app/src/components/Greeting.js:

import React from 'react';

const Greeting = ({ name }) => {
  return <h3>Hello from Remote App, {name}!</h3>;
};

export default Greeting;

remote-app/webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  devServer: {
    port: 3001,
  },
  output: {
    publicPath: 'http://localhost:3001/',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react'],
          },
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        './Greeting': './src/components/Greeting',
      },
      shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

Key points in remote-app/webpack.config.js:

  • name: 'remoteApp': A unique name for this remote application.
  • filename: 'remoteEntry.js': The file that will contain the manifest of exposed modules.
  • exposes: { './Greeting': './src/components/Greeting' }: This makes our Greeting component available to other applications under the alias ./Greeting.
  • shared: { react: { singleton: true }, 'react-dom': { singleton: true } }: Tells Webpack to share React and ReactDOM. singleton: true ensures only one instance of these libraries is loaded across all federated modules, preventing conflicts and reducing bundle size.

2. The Host Application (host-app)

This app consumes the Greeting component from remote-app.

host-app/src/App.js:

import React, { Suspense } from 'react';

// Dynamically import the Greeting component from the remote app
const RemoteGreeting = React.lazy(() => import('remoteApp/Greeting'));

const App = () => (
  <div>
    <h1>Host Application</h1>
    <Suspense fallback={<div>Loading Remote Greeting...</div>}>
      <RemoteGreeting name="CoddyKit Learner" />
    </Suspense>
  </div>
);

export default App;

host-app/webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  devServer: {
    port: 3000,
  },
  output: {
    publicPath: 'http://localhost:3000/',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react'],
          },
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'hostApp',
      remotes: {
        remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
      },
      shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

Key points in host-app/webpack.config.js:

  • name: 'hostApp': The unique name for our host application.
  • remotes: { remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js' }: This is where the magic happens. We tell the host to look for a remote application named remoteApp at the specified URL. Webpack will then fetch remoteEntry.js from that URL to discover its exposed modules.
  • shared: { react: { singleton: true }, 'react-dom': { singleton: true } }: Similar to the remote, we share React and ReactDOM. This ensures that both host and remote use the same instance of React, preventing potential issues and optimizing bundle size.

When you run both applications (remote-app on port 3001 and host-app on port 3000), the host application will dynamically load and render the Greeting component from the remote application. This simple example demonstrates the core power of Module Federation: runtime code sharing and integration.

Benefits of Micro Frontends with Module Federation Revisited

By leveraging Module Federation, the benefits of Micro Frontends become truly tangible:

  • Autonomous Teams & Independent Deployments: Teams can develop, test, and deploy their specific micro frontends without coordination overhead or fear of breaking other parts of the system.
  • Scalability & Flexibility: Easily scale development efforts by adding more teams and micro frontends. Experiment with new technologies without rewriting the entire application.
  • Enhanced Performance: Shared dependencies reduce overall bundle size, and dynamic loading of micro frontends via React.lazy (or similar mechanisms) improves initial load times.
  • Improved Developer Experience: Smaller, focused codebases mean faster local builds, easier debugging, and a clearer understanding of responsibilities.
  • Gradual Migration: Module Federation is excellent for incrementally migrating legacy monoliths to a micro frontend architecture, allowing you to replace parts piece by piece.

Your First Steps into the Federated World

Ready to get started? Here's a quick checklist:

  1. Ensure Webpack 5: Module Federation is a core feature of Webpack 5. Make sure your projects are using it.
  2. Understand Core Concepts: Grasp the ideas of "host," "remote," "exposes," and "remotes."
  3. Start Simple: Begin with a basic setup: one host and one remote application, just like our "Hello World" example.
  4. Experiment with Shared Dependencies: See how sharing common libraries impacts your bundle size and application behavior.

Conclusion

Micro Frontends, powered by Webpack 5's Module Federation, represent a significant leap forward in building scalable, maintainable, and high-performance web applications. They empower development teams to work more independently, adopt new technologies with less risk, and deliver features faster. This introductory guide has only scratched the surface of what's possible.

In our next post, we'll dive into Best Practices and Tips for building robust Micro Frontend architectures. Stay tuned to CoddyKit for more insights on mastering modern software development!

ProgrammingTutorialCoddyKit

Enjoyed this article?

Explore more tutorials and insights to level up your coding skills.

Browse All Articles →