Implementing Micro Frontends in React

Ekinzdaviz
4 min readMar 29, 2024

--

Photo by Ilya Pavlov on Unsplash

Introduction

Micro frontends are an architectural style where a frontend application is decomposed into smaller, semi-independent “micro” applications. Each micro frontend is responsible for rendering a portion of the user interface and can be developed, deployed, and maintained independently. This approach aligns with the microservices architecture in the backend, promoting scalability, maintainability, and flexibility. In this article, we will explore how to implement micro frontends in React, including the benefits, key concepts, and practical steps.

Benefits of Micro Frontends

  1. Scalability: Micro frontends allow teams to scale development by enabling parallel work on different parts of the application.
  2. Independence: Teams can independently develop, test, and deploy their micro frontends without affecting the entire application.
  3. Flexibility: Different micro frontends can use different technologies and frameworks if necessary, allowing teams to choose the best tool for the job.
  4. Maintainability: Smaller, more manageable codebases reduce complexity and improve maintainability.

Key Concepts

  1. Micro Frontend Architecture: The overall application is divided into smaller, self-contained units. Each micro frontend handles a specific business domain or feature set.
  2. Integration: Micro frontends are integrated into a single user interface, often through a composition layer that ensures they work together seamlessly.
  3. Communication: Micro frontends need to communicate with each other. This is typically achieved through shared state, events, or APIs.

Practical Steps to Implement Micro Frontends in React

Step 1: Define the Architecture

Before diving into the implementation, it’s crucial to define the architecture of your micro frontend application. Decide how to split the application into smaller parts. Common strategies include splitting by page, domain, or feature.

Step 2: Choose an Integration Method

There are several ways to integrate micro frontends:

  1. Iframe-Based Integration: Simple to implement but can lead to performance issues and complicated inter-frame communication.
  2. Build-Time Integration: Combine micro frontends at build time using tools like Webpack Module Federation.
  3. Run-Time Integration: Load micro frontends dynamically at runtime. This can be achieved through iframes, JavaScript includes, or micro frontend frameworks like Single-SPA or Piral.

Step 3: Set Up the Host Application

The host application acts as the container for the micro frontends. It handles navigation and global state management.

  1. Create a new React application:
npx create-react-app host-app
cd host-app

2. Install dependencies for micro frontend integration:

npm install single-spa react-router-dom

3. Configure Single-SPA in the host application:

// src/index.js
import { registerApplication, start } from "single-spa";
import { createBrowserHistory } from "history";
import React from "react";
import ReactDOM from "react-dom";
import { Router } from "react-router-dom";
import App from "./App";

const history = createBrowserHistory();

ReactDOM.render(
<Router history={history}>
<App />
</Router>,
document.getElementById("root")
);

registerApplication({
name: "@my-org/navbar",
app: () => System.import("@my-org/navbar"),
activeWhen: ["/"],
});

start();

Step 4: Develop a Micro Frontend

Next, create a micro frontend that will be integrated into the host application.

  1. Create a new React application for the micro frontend:
npx create-react-app navbar
cd navbar

2. Install dependencies and configure Single-SPA:

npm install single-spa-react

3. Export the micro frontend as a module:

// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import singleSpaReact from "single-spa-react";
import Navbar from "./Navbar";

const lifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: Navbar,
errorBoundary(err, info, props) {
return <div>Error in Navbar</div>;
},
});

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

4. Deploy the micro frontend: Deploy the micro frontend to a static file server or CDN. Ensure the URL is accessible to the host application.

Step 5: Integrate the Micro Frontend

Update the host application to load and render the micro frontend.

  1. Configure Webpack Module Federation (Optional): For advanced use cases, configure Webpack Module Federation to share dependencies between the host and micro frontends.
  2. Register the micro frontend in the host application:
// src/index.js
registerApplication({
name: "@my-org/navbar",
app: () => System.import("http://localhost:3001/navbar.js"),
activeWhen: ["/"],
});

start();

Step 6: Enable Communication Between Micro Frontends

Micro frontends often need to communicate. Use shared state, event buses, or custom events to facilitate communication.

  1. Shared State Example:
// host-app/src/state.js
import { createContext, useContext, useState } from "react";

const GlobalStateContext = createContext();

export const useGlobalState = () => useContext(GlobalStateContext);

export const GlobalStateProvider = ({ children }) => {
const [state, setState] = useState({ user: null });

return (
<GlobalStateContext.Provider value={[state, setState]}>
{children}
</GlobalStateContext.Provider>
);
};
// host-app/src/index.js
import { GlobalStateProvider } from "./state";

ReactDOM.render(
<GlobalStateProvider>
<Router history={history}>
<App />
</Router>
</GlobalStateProvider>,
document.getElementById("root")
);

2. Using Global State in a Micro Frontend:

// navbar/src/Navbar.js
import React from "react";
import { useGlobalState } from "host-app/state";

function Navbar() {
const [state] = useGlobalState();

return <div>Welcome, {state.user ? state.user.name : "Guest"}</div>;
}

export default Navbar;

Conclusion

Implementing micro frontends in React can significantly enhance the scalability, maintainability, and flexibility of your applications. By decomposing a large application into smaller, independently deployable units, you can leverage parallel development, adopt different technologies, and improve the overall developer experience. While the setup might initially seem complex, tools like Single-SPA and Webpack Module Federation simplify the integration process, making it easier to manage and maintain micro frontends. As with any architectural choice, it’s essential to weigh the benefits against the complexity to ensure it aligns with your project’s needs.

--

--