In our previous article, we covered the tools and technologies for building microfrontends, including a step-by-step guide to setting up a microfrontend architecture using Single-Spa.
Now, let's explore specific microfrontend projects and understand how different technologies can be used together to create a cohesive application.
We will also discuss how to manage communication between these microfrontends to ensure a seamless user experience.
And finally we'll provide links to different repositories we created on GitHub for each microfrontend described, so you can clone and run the entire project, play with it, look at the code, or use it as reference.
Overview of Microfrontend Projects
To illustrate the potential of microfrontends, let's take a look at an example setup where we have divided a large-scale application into different microfrontend projects:
- Navigation: Built using React, this microfrontend is responsible for rendering the main navigation bar across the application.
- Products: Developed with Vue, this microfrontend displays product listings and details. It focuses on the user interface for browsing products.
- Checkout: Built using Angular, this microfrontend handles the checkout process, including the shopping cart and payment flow.
- Utility Module: Created with RxJS and Single-Spa, this microfrontend manages shared utilities and handles communication between different parts of the application.
Each of these microfrontends is an independent application that can be developed, tested, and deployed separately. Let's explore each one in more detail.
We mix all this techs to show the possibilities of what you can do, in a real project you’ll probably have 1 or 2 frameworks at most. And in my personal opinion it is not a good practice to mix them all, just because you can do it, doesn't mean you should do it.
Navigation Microfrontend (React)
The Navigation microfrontend provides a consistent navigation experience across the application. It is built using React and serves as a shared component for the entire application.
By developing the navigation as a microfrontend, it can be updated independently of the other parts of the application. For example, if there is a design change or a new menu item needs to be added, the navigation team can make those changes without affecting the rest of the application.
Key Considerations: Make sure that navigation seamlessly integrates with other microfrontends. Any changes in routes or URLs need to be carefully coordinated with other microfrontends to ensure a smooth user experience.
Products Microfrontend (Vue)
The Products microfrontend handles the product catalog and is built using Vue. This microfrontend is responsible for displaying product listings, product details, and filtering options.
Vue was chosen for its lightweight nature and its ease of integration into existing applications, making it a good choice for developing feature-focused microfrontends like the product catalog.
Key Considerations: Ensure consistent styling across the entire application. Vue components should follow a shared design system to maintain a consistent look and feel across the application.
Checkout Microfrontend (Angular)
The Checkout microfrontend is built using Angular and focuses on the checkout experience, including handling the shopping cart, customer information, and payment flow.
Angular is a good choice for this part of the application due to its strong support for building complex forms, as well as its dependency injection system, which can simplify state management within the checkout process.
Key Considerations: The checkout microfrontend must interact smoothly with the products microfrontend to ensure that products added to the cart are correctly carried over to the checkout process.
Utility Module (RxJS and Single-Spa)
The Utility Module is built with RxJS and Single-Spa to manage cross-microfrontend communication. This module serves as a shared utility that can be used to share state, trigger events, or communicate between different microfrontends.
RxJS is particularly useful for implementing the Observer Pattern, allowing different microfrontends to subscribe to events and react accordingly. For instance, if a user adds an item to their cart in the Products microfrontend, the Checkout microfrontend can be notified through the utility module to update the cart contents.
Key Considerations: Communication between microfrontends should be designed in such a way that they remain loosely coupled. Using RxJS allows for asynchronous communication without creating tight dependencies between different microfrontends.
Managing Communication Between Microfrontends
Effective communication between microfrontends is crucial for maintaining a seamless user experience. There are several approaches to manage this communication, depending on the complexity of the application and the requirements of the microfrontends.
Global Event Bus
A global event bus is a simple way to manage communication between microfrontends. It acts as a central hub where microfrontends can publish and subscribe to events. This is similar to an event emitter, allowing different parts of the application to communicate without directly referencing each other.
In our setup, RxJS can be used as a global event bus, allowing microfrontends to broadcast events (e.g., item added to cart) and enabling other microfrontends to react accordingly.
Shared State Management
In more complex scenarios, a shared state management solution can be implemented. This involves creating a global state that is accessible to all microfrontends, allowing for consistent data across different parts of the application.
Libraries like Redux or MobX can be used for state management, but it is important to weigh the pros and cons of introducing a centralized state.
For microfrontends, it is crucial to maintain independence, so any shared state should be minimal and well-defined. For example, if you have to share a lot of state between two microfrontends, that's usually a sign that you should merge the logic into a single microfrontend, as always this will depend on several factors, so analyze and evaluate the trade-offs based on your needs.
Cross-Frontend Communication with RxJS
As mentioned earlier, RxJS is well-suited for managing communication between microfrontends. By using subjects and observables, microfrontends can subscribe to changes and react accordingly.
For example, the Products microfrontend can use an RxJS subject to broadcast when an item is added to the cart, and the Checkout microfrontend can subscribe to this event to ensure that the cart is updated.
Ensuring Consistency Across Microfrontends
One of the challenges of using microfrontends is ensuring a consistent user experience across different parts of the application. Here are some best practices to help achieve consistency:
- Shared Design System: Establish a shared design system that includes reusable components, styles, and guidelines. This ensures that all microfrontends follow the same visual language and provide a cohesive user experience.
- Centralized Utilities: Create centralized utilities for common functionality (e.g., API calls, authentication) to avoid duplication and ensure consistent behavior across microfrontends.
- Communication Contracts: Define clear communication contracts between microfrontends. This helps prevent breaking changes and ensures that all microfrontends can integrate seamlessly without unexpected issues.
GitHub Projects
In the following links you can find the implementation of the different projects we went through:
Conclusion
Exploring different microfrontend projects highlights the flexibility of a microfrontend architecture. By splitting a large application into smaller, independently deployable units, teams can work autonomously while ensuring that the overall user experience remains consistent.
Managing communication between microfrontends is key to providing a cohesive application, and tools like RxJS can help facilitate this communication in a loosely coupled manner.
In the next and final article of this series, we will explore best practices and lessons learned from implementing microfrontends, along with a practical example of adding a new microfrontend to the existing architecture.
Top comments (0)