In front-end dev, micro-frontends, a branch of microservices, are popular.
Despite many JS tools, libraries, and frameworks, their optimal use is confusing.
Micro-frontend architecture offers flexibility in choosing libraries and frameworks, but it's challenging, especially in performance and complexity.
Micro-frontends are technical embodiments of business subdomains, characterized by:
Micro-frontends and components serve different purposes and are not mutually exclusive. While components represent reusable UI elements (e.g., buttons with various properties like labels, icons, and animations), micro-frontends encapsulate a technical representation of a business subdomain, enabling independent implementation and deployment. The critical distinction lies in their scope and autonomy; micro-frontends operate independently and are domain-aware, contrasting with components that are often context-driven.
To avoid this anti-pattern, delineate micro-frontend boundaries based on business subdomains and avoid treating components as micro-frontends, as the latter represent entire business domains. For further clarity, refer to the What's the Difference Between a Component and a Micro-Frontend? documentation page.
Setting up a micro-frontend involves deciding on a domain and establishing an application shell. Micro-frontends offer the freedom to choose any framework, but this freedom comes with its challenges:
In cases where multiple teams use different technologies, a unified approach using a single framework is often more beneficial, avoiding inconsistency and negative user experiences. However, a multiframework approach can be advantageous in certain scenarios, like fostering a dynamic development environment that accelerates business logic deployment without impacting production.
Designing micro-frontends that attempt to cover too broad a functionality spectrum can complicate communication and integration within an application. Focusing on single responsibilities and utilizing appropriate communication patterns (e.g., event emitters for intra-view communication) can enhance modularity and maintainability.
Solutions:
Independence is a hallmark of both microservices and micro frontends. However, this can lead to "dependency hell," a term used to describe the frustration of managing software packages with interdependent versions. For example, if a core library used by multiple micro frontends updates, it can cause conflicts with existing implementations or extensions.
Favoring composition over inheritance and maintaining clear boundaries between shared resources can alleviate these issues. It's crucial to evaluate the necessity of external dependencies and strive for minimal coupling to avoid escalating complexity.
To mitigate this:
Multiple micro-frontends making redundant calls to the same API endpoints can strain the backend infrastructure and degrade performance. Rationalizing the frontend architecture to minimize duplicate requests, considering API gateways, and optimizing backend services are vital steps in mitigating this issue.
Solutions:
Micro-frontends sometimes need to communicate, especially in UIs managed by different teams. For instance, updating a mini-basket when a user adds an item requires communication among micro frontends. While a global state might seem like a straightforward solution, it contradicts the principle of independence in micro-frontends.
Employing event-driven communication and ensuring micro-frontends remain loosely coupled through well-defined interfaces can preserve independence and facilitate easier integration and evolution of the ecosystem.
Alternatives include: