Microfrontends (MFE) are an architectural approach that allows large web applications to scale quickly and efficiently while minimizing code duplication. Similar to backend microservices, MFEs divide applications into independent projects without sacrificing cohesion. This enables agile development by multiple teams without the need to duplicate common code.
Microfrontends vs Component Libraries
One common question teams often ask is whether they need a microfrontend or a component library. While the line between them may not always be well-defined, let's explore how an application built with a web component framework like React behaves with each approach:
Component library:
- Injected into the application at build time, resulting in the library's code being included in the final application bundle.
- Requiring a new release of both the library and the clients to update.
- Primarily focused on reusing visual components or utilities, often lacking business logic hosting.
Microfrontends:
- Injected at runtime, with no dependency added during development. Only the URL where the bundle can be downloaded is provided. When invoked, the application downloads and injects the MFE.
- Clients can be updated simply by releasing the MFE in the project. Since it is injected at runtime, there is no need to rebuild the clients.
- MFEs act as standalone applications, enabling REST calls, execution of business logic, and display capabilities.
Considerations for Adoption 🐥
Typically, the backend holds most of the business logic for an application, while the frontend serves as a simplified representation. If the frontend's representation layer remains stable even as the backend scales, adopting a microfrontend architecture may not be advisable.
For new projects aimed at testing viability, it is not recommended to immediately adopt a microfrontend architecture. The time required to set up a productive environment should be used to assess the project's feasibility.
In summary, only use microfrontends when your code necessitates it. Listen to your code, diagnose it, and split the monolith only if necessary! 🤟
Splitting the Monolith 🔪
The process of splitting backend monoliths aligns closely with the work involved in adopting microfrontends. The goal is to identify application domains and determine if they contain enough entities to exist as separate projects.
🧪 For our e-commerce example, we could divide the project into teams responsible for product management, cart functionality, and sales. Each team represents an essential part of the business and is logical enough to be treated as an independent project.
In the backend, communication between the swarm of microservices is crucial, employing mechanisms such as events, REST, or gRPC. Similarly, in the frontend, we not only require communication between components (which we'll address in a future post), but also cohesive rendering of the application for the user. This is where the shell comes into play.
Shell: Split and Reassemble 🍱
The shell serves as the orchestrator of microfrontends, an independent project responsible for determining what to render based on various data, such as the router path or browser events.
Ideally, the shell should contain minimal business logic. It can handle user authentication, log publication in the ingest service, and manage common variables like the user's country. However, keep in mind that adding too much to the shell compromises independence.
🧪 In our e-commerce example, the shell would include the application's header with the company logo and various links leading to different sections, such as the user profile or home page. Additionally, the shell should be aware that any paths starting with
/product
should load the product microfrontend, paths starting with/cart
should load the cart microfrontend, and paths starting with/checkout
should load the sales microfrontend.
One Project, Multiple Microfrontends 🦄
It's important to note that when we talk about a project, we're not necessarily referring to a single microfrontend. A project can expose multiple microfrontends that can be consumed by the shell or other microfrontends. As previously mentioned, microfrontends act as web components, but they are injected at runtime, providing endless possibilities.
🧪 The cart team, for example, exposes two microfrontends. The first one is the cart page, which displays information about products, units, prices, and the final cost. This microfrontend is loaded in the shell when the user accesses the
/cart
path, as we discussed earlier. The team also exposes a cart icon microfrontend, which appears in the header of the website at all times.
This article serves as an introduction to the concept of microfrontends, and subsequent articles will delve into more advanced topics, such as microfrontend communication, shared state management, and more!
Stay tuned for the next articles in this series as we explore the exciting world of microfrontends.
Top comments (0)