Micro Frontends — Revisiting the monolithic approach to UI development
Nowadays, most companies prefer microservices architecture over monolithic applications. The main reason is that each service can be developed, deployed, and scaled independently. However, this style of development is typically followed only for backend services. The UI, on the other hand, is usually developed as a monolithic Single Page application using common UI libraries/frameworks like React, Angular, or Vue.js. This approach is fine if your application UI is relatively small. However, as it grows, you will face similar issues to those you faced for a monolithic backend. Some common issues include:
- A large codebase, which can make it difficult to understand.
- Increased build time for the UI application.
- Difficulty in updating existing application libraries or adopting new tools and libraries.
- Multiple teams working on the same codebase, which can cause dependency issues.
- Backend services and user interface developed by separate teams, resulting in delayed release cycles and lack of full ownership by teams.
One common solution to the problems mentioned above is micro frontends. Micro frontends is an architectural style that extends the concepts of microservices architecture pattern to frontend development.
The idea behind Micro Frontends is to think about a website or web app as a composition of features which are owned by independent teams. Each team has a distinct area of business or mission it cares about and specialises in. A team is cross functional and develops its features end-to-end, from database to user interface. — micro-frontends.org
Benefits of Micro Frontends
There are several benefits to adopting the micro frontends architectural style, including:
- Simple codebase, easy to develop and test.
- Independent deployment, resulting in improved build and test times.
- Teams can easily adopt new tools and incrementally update libraries.
- Autonomous teams own a business functionality end-to-end, resulting in faster time-to-market.
- The micro frontends architectural style can also be used to combine multiple related applications into a single application, improving the overall user experience.
Drawbacks of Micro Frontends
While micro frontends can be useful, they are not a silver bullet. Like microservices, micro frontends have some drawbacks:
- The initial setup as well as multiple deployment pipelines can become complex, so it is important to automate the setup and deployment process properly.
- This approach can lead to inconsistencies in the look and feel or implementation of different UI modules. However, this issue can be resolved by introducing common shared modules or libraries that can be used across multiple micro frontends.
- Properly defining the boundaries and communication among micro frontends is crucial. Too much dependency between micro frontends can negatively impact development and testing.
- If not implemented properly, this can result in increased page sizes.
Implementation Approaches
The most important steps in adopting micro frontends are identifying UI boundaries and determining how to integrate different UI modules into one application. UI boundaries can be defined in several different ways. A common approach is to combine one or more pages or fragments that correspond to one business capability into one micro frontend. Similarly, each business capability will have its own micro frontend. An application shell or container is used to combine multiple micro frontends into a single application. The responsibilities of the application shell include:
- The application shell itself can be a micro frontend and will be loaded on application startup.
- It orchestrates the integration of different micro frontends into a single application. The application shell contains HTML placeholders where each micro frontend will be loaded based on some configurations.
- Common shared libraries should be part of the application shell to reduce page payload size.
- Cross-cutting concerns like authentication/authorization, logging, and inter-page communication should be implemented as part of the application shell. APIs should be exposed by the shell to access these inside micro frontends.
Build-Time Composition
In this approach, micro frontends are integrated during build time. One way to do this is by using NPM packages. Different UI modules are published as separate NPM packages, and during build time, they are fetched from repositories and built as a single application. This approach might be useful for certain use cases, but it has a disadvantage: the deployment is not independent. Even if we make a change in just one of the micro frontends, we have to rebuild and redeploy the entire application.
Server-Side Composition
One way to implement micro frontends is to combine UI fragments at the server-side before sending a response to the browser. Pages composed using server-side includes can be an example of server-side composition. For micro frontends developed in React or Angular, the setup can become more complex. In this case, the application shell will be a dedicated service running on the server, which takes care of server-side rendering of UI components in each micro frontend, and is then composed as a single HTML page before sending a response to the browser. This approach is more useful if SEO is important for your application. One of the downsides of this approach is the delay associated with server-side rendering. However, latency and performance issues can be addressed by using mechanisms like template caching.
Client-Side Composition
One common approach for integrating micro frontends is through client-side composition. With this approach, the application shell is loaded in the browser at startup. It then fetches different micro frontends, which are deployed in different URLs based on some manifest or configuration. The micro frontends are then integrated at runtime inside placeholders provided by the application shell.
There are several ways to implement client-side composition, such as using iframes or with techniques like Module Federation. While iframes can provide a sandboxed environment for each micro frontend, they can also present challenges related to application responsiveness. If you need to share modules or common code across micro frontends, Module Federation is a better choice. In my opinion, Module Federation is better suited for implementing client-side composition compared to iframes.
Webpack 5 comes with a Module Federation plugin that makes it easy to implement micro frontends using client-side composition.
Conclusion
Micro frontends are gaining more and more popularity nowadays. Although monolithic UI still makes sense for many use cases, micro frontends architecture can be used to split complex UI into simple, easy-to-manage, and independent UI services. Before adopting this approach, we must ensure that the boundaries and dependencies between micro frontends are clearly defined. Moreover, investments should be made in the initial setup, including tooling and automation.