Micro Frontends with Module Federation
What are Micro Frontends?
Micro Frontend architecture is an approach where a website or web application is decomposed into multiple individual, loosely coupled, applications. We can think about these applications as microservices for the frontend, called Micro Frontends. Each one can be maintained separately, but there will be a shell application, which loads all of them.
Let's say we have a single page application, an online shop. This application grew over time, containing multiple business areas. It became harder to maintain it, the development and deployment speed decreased. We want to split this application into multiple business areas, and have different teams working on these areas, while still having a single page application. It could also be only one team working on all of the areas, it depends on the application's size and team cappacity. For this split, we need a shell application, which loads all the other applications. This one could either be owned by one team, or be in shared ownership. Then we want to have an application (project) for each business area (product, cart, payment). Each team would have one or multiple projects in its ownership.
Benefits and drawbacks of Micro Frontends
The major benefits of Micro Frontends include: increased development and deployment speed, better maintainability, independent and autonomous teams, flexibility in choosing the technical stack for each team and lower risk of bugs.
We should always keep in mind the drawbacks, and decide for each application if we have more benefits than drawbacks. Some of the drawbacks that can appear are: redundant dependencies (same libraries with different versions), inconsistent UI/UX, lower performance, communication issues between teams and complexity.
Many of these drawbacks can be avoided by having constant collaboration and alignment between teams. This is somewhat in contradiction with the benefit we mentioned, having independent and autonomous teams. But, independent teams does not mean complete isolation from other teams. We need to find the right balance.
How to decide if we need Micro Frontends?
Most applications start as monoliths, containing all the pages, components, business logic, etc. With time an application can grow, the development speed decreases and it becomes harder to maintain it. Usually this is when we think about refactoring, splitting into multiple sub-projects or projects. The negotiation wih business team starts, we need to allocate some time to address these problems. This could be prevented if the application is designed from the beginning having these business areas in mind.
When we start a new application, we should make a conscious decision if a Micro Frontend setup is needed. If we already see multiple business areas and we have multiple people working on the same application, it might make sense to start with Micro Frontends. The setup will take more time, but it is a small sacrifice for the long term benefits.
If we see some business areas, but we are not convinced Micro Frontends are needed, we could start with only one application, but keeping Domain-Driven Design in mind. For small applications with only a few features, the complexity of this setup outweighs the benefits. If we already have a large application, with multiple people or teams working on it, we might have problems like decreased development speed or higher risk of bugs. When it becomes difficult to maintain a large application, we need to find a way to split the application into multiple smaller ones, keeping them loosely coupled. This is when Micro Frontends come into picture.
How to implement Micro Frontends?
The multiple possible ways to implement Micro Frontends can be divided in three categories: build-time integration, server-side composition and run-time integration. There are also some libraries or frameworks that can reduce the initial effort which is needed to implement this setup, but these can be opinionated and can introduce security vulnerabilities or technical debt, if not maintained properly.
This is one of the issues Webpack's Module Federation tries to solve. Module Federation is not a framework, just a webpack plugin, so it will not introduce dependencies and we have freedom and flexibility in how we build our applications. It is framework agnostic, it can be used with any framework.
To implement Micro Frontends with Module Federation, we need a shell application, where we integrate all the other applications, at run-time. This means, when an application changes, we do not need to bump its version in the shell application or to redeploy the shell application.
Another important benefit is that it minimizes dependency duplication, by having shared dependencies (e.g. react, react-dom, design system can have the same version across all applications). It also supports lazy loading bundles, so the modules are loaded only when needed, this improves performance.
As stated already, we will have at least some dependencies between the teams working on Micro Frontend applications. The shell application might be in shared ownership, and we can also have shared components or a design system library for which we want all the teams to use the same version, in order to have a consistent UI/UX. We need some kind of collaboration between them. For now, let's focus on the benefits of Micro Frontends, and we will discuss more about this topic in an upcoming blog post. Until then, you can find a list of examples with different use cases here.