DEV Community

Cover image for Micro-Frontends with React: A Comprehensive Guide
Dhrumit Kansara
Dhrumit Kansara

Posted on

Micro-Frontends with React: A Comprehensive Guide

As web applications grow in complexity, the need for scalable and maintainable architectures becomes paramount. Micro-frontends offer a solution by breaking down monolithic front-end applications into smaller, manageable pieces. In this post, we’ll explore the concept of micro-frontends, how to implement them using React, and the benefits they bring to your development process.

What are Micro-Frontends?

Micro-frontends extend the microservices architecture to the front end. Instead of a single monolithic application, micro-frontends allow you to develop and deploy individual features or sections of your application independently. Each team can own a specific part of the application, leading to better scalability and maintainability.

Key Characteristics of Micro-Frontends:

Independently Deployable: Each micro-frontend can be developed, tested, and deployed independently.
Technology Agnostic: Teams can choose different technologies for different micro-frontends, allowing for flexibility.
Team Autonomy: Teams can work independently, reducing dependencies and bottlenecks.

Why Use Micro-Frontends?

Scalability: As your application grows, micro-frontends allow you to scale development across multiple teams.
Faster Development: Independent deployments mean faster release cycles and reduced time to market.
Improved Maintainability: Smaller codebases are easier to manage, test, and refactor.

Implementing Micro-Frontends with React

  • Choose a Micro-Frontend Architecture There are several approaches to implementing micro-frontends. Here are two popular methods:

Iframe-based: Each micro-frontend is loaded in an iframe. This approach provides strong isolation but can lead to challenges with communication and styling.

JavaScript Bundles: Each micro-frontend is a separate JavaScript bundle that is loaded into a single application. This approach allows for better integration and shared state management.

  • Setting Up a Micro-Frontend Application Let’s create a simple example using the JavaScript bundle approach. We’ll use Webpack Module Federation, a powerful feature that allows you to share code between different applications.

Step 1: Create Two React Applications
Create two separate React applications, one for the host and one for the micro-frontend.

npx create-react-app host-app
npx create-react-app micro-frontend
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure Webpack Module Federation
In the micro-frontend application, install the necessary dependencies:

npm install --save-dev webpack webpack-cli webpack-dev-server @module-federation/webpack
Enter fullscreen mode Exit fullscreen mode

Then, modify the webpack.config.js to expose your micro-frontend component:

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

module.exports = {
  // ... other configurations
  plugins: [
    new ModuleFederationPlugin({
      name: "micro_frontend",
      filename: "remoteEntry.js",
      exposes: {
        "./Button": "./src/Button", // Expose the Button component
      },
      shared: {
        react: { singleton: true },
        "react-dom": { singleton: true },
      },
    }),
  ],
};
Enter fullscreen mode Exit fullscreen mode

In the host-app, configure it to consume the micro-frontend:

// host-app/webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  // ... other configurations
  plugins: [
    new ModuleFederationPlugin({
      name: "host",
      remotes: {
        micro_frontend: "micro_frontend@http://localhost:3001/remoteEntry.js",
      },
      shared: {
        react: { singleton: true },
        "react-dom": { singleton: true },
      },
    }),
  ],
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Load the Micro-Frontend
In your host-app, you can now dynamically load the micro-frontend component:

// host-app/src/App.js
import React, { useEffect, useState } from "react";

const App = () => {
  const [Button, setButton] = useState(null);

  useEffect(() => {
    const loadButton = async () => {
      const { Button } = await import("micro_frontend/Button");
      setButton(() => Button);
    };
    loadButton();
  }, []);

  return (
    <div>
      <h1>Host Application</h1>
      {Button ? <Button label="Click Me!" /> : <p>Loading...</p>}
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode
  • Run the Applications Make sure to run both applications on different ports. For example, you can run the micro-frontend on port 3001 and the host-app on port 3000.
# In the micro-frontend directory
npm start -- --port 3001

# In the host-app directory
npm start
Enter fullscreen mode Exit fullscreen mode

Now, when you navigate to http://localhost:3000, you should see the host application loading the button from the micro-frontend.

Micro-frontends provide a powerful way to manage complex front-end applications by breaking them into smaller, independently deployable pieces. By leveraging React and tools like Webpack Module Federation, you can create a scalable architecture that enhances team autonomy and speeds up development. As you consider adopting micro-frontends, weigh the benefits against the complexity they introduce, and choose the approach that best fits your project needs.

Top comments (0)