Micro-Frontends with React: Splitting Your App for Scalability

  • Implement micro-frontends in React for scalable and modular applications

  • Improve flexibility and enable parallel development across teams

  • Enhance maintainability and scalability in large front-end projects

By Shamim Ahmed , Software Engineer
Last Update: 28 Nov 2024
Micro-Frontends with React: Splitting Your App for Scalability image

Building and maintaining large applications can feel like trying to manage a towering stack of Jenga blocks. As more features get added, the structure becomes more fragile and harder to work with. That’s where micro-frontends come in, offering a way to break down that massive stack into smaller, more manageable pieces that are easier to handle and less likely to topple.

In this blog, we’ll dive into what micro-frontends are, why they’re a game-changer for modern web development, and how you can start using them with React. To make it practical, we’ll also walk through a simple example.

What Are Micro-Frontends?

Imagine your frontend application as a big puzzle. A monolithic frontend puts all the pieces together into one giant, interconnected picture. While this works for smaller applications, it becomes a challenge to manage as the app grows. What if you could split the puzzle into smaller sections that can be worked on independently, by different teams, without constantly worrying about how the entire puzzle fits together? That’s the idea behind micro-frontends.

Micro-frontends are a way of breaking a large application into smaller, self-contained pieces. Each piece, or micro-frontend, can be developed, tested, and deployed independently. Think of it as applying the same principles of microservices to your frontend.

Why Use Micro-Frontends?

Here are some compelling reasons to give micro-frontends a shot:

  1. Independent Development
    Teams can focus on their own slice of the app without stepping on each other’s toes. For example, the team working on the shopping cart doesn’t need to worry about what’s happening with the user profile section.

  2. Faster Deployment
    Since each micro-frontend is independent, updates can be deployed individually without waiting for the entire app to be ready.

  3. Scalability
    Large teams can divide and conquer by working on different micro-frontends using the tools and frameworks they prefer.

  4. Resilience
    If one micro-frontend breaks, the rest of the application can keep running. This modular approach reduces the chances of a single bug bringing down the entire app.

  5. Easier Maintenance
    Smaller, focused codebases are easier to maintain and refactor than a sprawling monolith.

Key Architecture Concepts

  • Shell Application: The main application that hosts all micro-frontends. It handles routing and common dependencies.
  • Micro-Frontend Applications: Smaller applications responsible for specific features or sections of the UI.
  • Communication: Micro-frontends communicate via shared events or APIs.

Implementing Micro-Frontends with React

For this example, we'll build a simple dashboard with a Host App and two micro-frontends:

  1. User Management
  2. Analytics Dashboard

We'll use Module Federation from Webpack 5 for integrating these apps.

Step 1: Setting Up the Host Application

The Host App will act as the container.

npx create-react-app host-app --template typescript
cd host-app

Install dependencies:

npm install @module-federation/webpack-cli webpack webpack-cli

Modify webpack.config.js:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: "host",
      remotes: {
        userManagement: "userManagement@http://localhost:3001/remoteEntry.js",
        analyticsDashboard: "analyticsDashboard@http://localhost:3002/remoteEntry.js",
      },
      shared: { react: { singleton: true }, "react-dom": { singleton: true } },
    }),
  ],
};

 

Step 2: Creating the Micro-Frontend Apps

1. User Management

Create a new app:

npx create-react-app user-management --template typescript
cd user-management

Add Module Federation:

npm install webpack webpack-cli

Modify webpack.config.js:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: "userManagement",
      filename: "remoteEntry.js",
      exposes: {
        "./UserList": "./src/UserList",
      },
      shared: { react: { singleton: true }, "react-dom": { singleton: true } },
    }),
  ],
};

Create a User List Component (UserList.tsx):

import React from "react";

const UserList = () => {
  const users = ["Alice", "Bob", "Charlie"];
  return (
    <div>
      <h2>User Management</h2>
      <ul>
        {users.map((user) => (
          <li key={user}>{user}</li>
        ))}
      </ul>
    </div>
  );
};

export default UserList;

2. Analytics Dashboard

Repeat the process for the second micro-frontend, creating a component Analytics.tsx for analytics data.

Step 3: Integrating Micro-Frontends into the Host App

In the Host App, load micro-frontends dynamically:

import React, { Suspense } from "react";

const UserList = React.lazy(() => import("userManagement/UserList"));
const Analytics = React.lazy(() => import("analyticsDashboard/Analytics"));

function App() {
  return (
    <div>
      <h1>Host Application</h1>
      <Suspense fallback={<div>Loading User Management...</div>}>
        <UserList />
      </Suspense>
      <Suspense fallback={<div>Loading Analytics...</div>}>
        <Analytics />
      </Suspense>
    </div>
  );
}

export default App;

Step 4: Running the Apps

Run each app on different ports:

  1. Host App: http://localhost:3000
  2. User Management: http://localhost:3001
  3. Analytics Dashboard: http://localhost:3002

Benefits of This Setup

  • Independent Updates: You can deploy the User Management micro-frontend without touching the Analytics Dashboard.
  • Parallel Development: Different teams can own and manage each micro-frontend.
  • Scalable Architecture: As the app grows, new micro-frontends can be added effortlessly.

Challenges of Micro-Frontends

  • Increased Complexity: Managing multiple repositories and deployments can be challenging.
  • Performance: Loading multiple micro-frontends may increase initial load time.
  • Shared State: Managing shared state across micro-frontends requires careful planning.

Conclusion

Micro-frontends are a game-changer for building modern, scalable applications, especially when working with large teams or complex projects. By breaking down a big, monolithic app into smaller, independently deployable pieces, you make it easier for teams to work in parallel, roll out updates faster, and keep everything more manageable.

With React and tools like Module Federation, implementing micro-frontends doesn’t have to be complicated. It’s a great way to future-proof your application and ensure it can grow with your needs.

That said, micro-frontends aren’t a one-size-fits-all solution. They shine in large, scalable projects but might add unnecessary complexity to smaller apps.

Frequently Asked Questions

Here are some common ways micro-frontends can communicate with each other, explained in a straightforward way: APIs: Think of APIs as the messengers between modules. They let different parts of your app exchange data and functionality seamlessly. For example, one module might fetch user data and share it with another that needs it. Events: Events are like signals. One module can trigger an event when something important happens (like a button click), and other modules can listen and respond to those changes in real time. Shared Libraries: These are like community tools—shared pieces of code or state that all micro-frontends can access. This ensures consistency across your app while keeping things DRY (Don’t Repeat Yourself). Cookies: Perfect for sharing small bits of data, like user preferences or session tokens, across micro-frontends. They're simple and effective for keeping everything in sync. Custom Events: These are like regular events but with a twist. You can define your own event names and include custom data, giving you more flexibility in how your modules communicate. For example, you might create an event called userLoggedIn that sends user details to any module that needs them.

Author

About the Author

Hey, I'm Md Shamim Hossen, a Content Writer with a passion for tech, strategy, and clean storytelling. I turn AI and app development into content that resonates and drives real results. When I'm not writing, you'll find me exploring the latest SEO tools, researching, or traveling.

Trendingblogs
Get the best of our content straight to your inbox!

By submitting, you agree to our privacy policy.

Let's
Talk