Micro Frontends (MFEs) Without the Mess
Waqas Idrees
Software Architect | Full Stack | Azure | C# | .NET Core | React | Vue | Blazor | Data Engineering | Azure AI Services | Micro Frontends
In today’s evolving web landscape, Micro frontends (MFEs) have emerged as a powerful architectural pattern. They allow teams to work independently on different parts of an application, improving flexibility and speed. However, this approach comes with challenges, and one of the biggest is library conflicts and inconsistent styling.
Each MFE (micro frontend) may use different JavaScript frameworks, UI libraries, or CSS libraries, which can lead to integration headaches. In this blog, we'll explore these challenges and a structured approach to solving them. But first, let’s briefly introduce micro frontends to those who don't know much about it.
What Are Micro Frontends (MFEs)?
Micro frontends apply the microservices concept to the frontend. Instead of having one large monolithic frontend, the UI is made up of multiple, smaller applications (MFEs) that work together.
Key Features of Micro Frontends:
While this approach provides flexibility, it can introduce inconsistencies in code, UI components, and dependencies. Allowing each team to pick its own framework, UI and CSS library may sound good in theory, but in the long run, it can create serious problems.
The Case for Standardization
Framework Standardization
In my view, it is better if all teams use one approved framework or library for all MFEs. Over time, If a framework or library like Knockout.js, Backbone.js, or jQuery etc. becomes outdated, teams can switch to a new framework for future development. This way, coding standards remain consistent, and it makes it easier to move developers between MFE teams, reducing the learning curve.
Let's say we have finalized React as the framework for development.
The Next Challenge: Standardizing Libraries
Even when all teams use the same framework, there is still a chance that teams might choose different libraries (like Bootstrap or Tailwind, Material UI, or Joy UI, Axios or Fetch). We can fix this by also approving a single library for each task across all MFEs. For example, let's say we've finalized Material UI as the component library.
Component Library Challenges
Even after selecting Material UI as the component library, several problems can still arise:
This challenge isn't limited to only component libraries. For example, consider network libraries like Axios or Fetch. If they become obsolete or develop vulnerabilities, replacing them individually across every MFE would be a significant challenge.
The Best Solution: A Shared Library
A shared library is the most effective way to maintain consistency across MFEs. Instead of adding a library (like Material UI) directly into each MFE, we build a separate, shared library that contains all the UI components.
领英推荐
This ensures that:
Let's take example of Material UI again. Instead of adding Material UI directly to every MFE, we can build a separate component library that includes Material UI and creates our own versions of the controls. Each MFE then uses this common library. You can share it as an npm package or use module federation based on your project’s needs.
Example: A Standard Button Component
Here is a simple version of a Material UI button in our component library:
// Button.js
import React from 'react';
import MuiButton from '@material-ui/core/Button';
const variantMapping = {
primary: 'contained', // Primary action style
secondary: 'outlined', // Secondary action style
};
export const Button = ({
variant = 'primary', // Accepts 'primary' or 'secondary'
onClick,
children,
...props
}) => {
const mappedVariant = variantMapping[variant];
return (
<MuiButton variant={mappedVariant} onClick={onClick} {...props}>
{children}
</MuiButton>
);
};
Now, every micro frontend must use this shared button instead of directly importing Material UI’s button. If we ever need to switch to another UI library (for example, Joy UI), we only update the component library rather than every MFE. Consider this alternative implementation using Joy UI:
// Button.js
import React from 'react';
import JoyButton from '@mui/joy/Button';
const variantMapping = {
primary: 'solid', // Primary action style in Joy UI
secondary: 'soft', // Secondary action style in Joy UI
ghost: 'plain', // Minimal style option
};
export const Button = ({
variant = 'primary', // Accepts 'primary', 'secondary', or 'ghost'
onClick,
children,
...props
}) => {
const mappedVariant = variantMapping[variant];
return (
<JoyButton variant={mappedVariant} onClick={onClick} {...props}>
{children}
</JoyButton>
);
};
Documentation Challenges
When creating shared libraries on top of existing ones like Axios, Fetch, or Globalize, developers might not need extensive documentation. However, for component libraries documentation is essential. For example, Material UI has great documentation and demos. However, if you build your own component library, creating and keeping documentation up to date for all teams can be a big task. If teams don’t know how to use the components, they might still create their own versions, leading to inconsistencies. Fortunately, there are tools to help with this.
Some Tools for Documentation & UI Testing
You can consider following tools/libraries to document UI and Components
Using these tools ensures that all teams have access to the guidelines and documentations and makes component adoption seamless.
Bringing It All Together
By combining MFE architecture with shared libraries, teams can work independently while maintaining consistency across all MFEs and avoiding integration challenges. The key is to standardize not only the UI components but also all other dependencies, such as network libraries and internationalization libraries.
Key Takeaways:
? Adopt one framework and a set of common libraries for all MFEs to ensure consistent coding and styling standards.
? Build centralized libraries for recurring functionalities, whether UI components, network utilities, or other dependencies, to simplify version management and updates across all MFEs.
? Use tools like Storybook, Ladle, or Histoire to provide clear, accessible documentation and guidelines that help all teams stay aligned.
This structured approach helps teams achieve flexibility without sacrificing consistency, making micro frontend development more scalable and maintainable.
At the end, I would like to extend my sincere thanks to Jeffrey Ulman for his guidance during my last assignment. His mentorship played an important role in shaping the ideas presented in this blog.
Well written. Spot on
ERP Specialist / Product Manager / Technical Business Analyst / Technical Project Manager / ERP Techno Functional Consultant
3 周Feeling great delight in my heart to know it coming from you, Waqas Idrees.
Sr Software Engineer at Stewart Title
3 周Very informative