
Introduction
Web development is constantly evolving, with innovative approaches and technologies shaping how we build and maintain applications. One such approach that has gained significant attention among frontend developers is the use of micro-frontends.
Micro-frontends involve breaking down large, monolithic frontends into smaller, more manageable components. Each micro-frontend is an independent, self-contained unit of code that handles a specific responsibility within the overall application, often corresponding to a distinct section of a webpage.
The advantage of micro-frontends is their autonomy. These components can be developed, deployed, and maintained separately, enabling faster development cycles and easier updates. By communicating through APIs, micro-frontends can interact seamlessly while being built with a variety of technologies and frameworks, giving teams the flexibility to choose the best tools for each part of their application.
How we are using micro-frontends to accelerate our business
Blip, as part of the Flutter Entertainment Group, is looking to adopt micro-frontend technology across all sports platforms. As a global group, we have several distinct products that need a consistent design interface, way of working and user experience. With this in mind, we want multiple teams to contribute faster and to be able to reuse content while building the same apps, so that what changes is configuration, not code. This allows, for example, to reuse events search UI instead of fully developing it each time.
What is so good about it?
Easier coordination among teams
Coordinating and delivering updates simultaneously can be challenging when different teams are working on distinct features for the same product. With micro-frontends, each team can manage their deployment process without affecting other teams who might be testing out experimental code concurrently. This makes it possible to carry out releases and updates with features that are already live in a more planned and effective manner.
More time to build new features
As micro-frontends allow code reusability and sharing, teams can focus on creating new features instead of duplicating what has already been done every time it is necessary to implement a common functionality. This allows faster feature rollout.
Flexibility and independence
This kind of architecture for creating frontend apps gives frontend teams the same flexibility and speed that microservices give backend teams. This happens by segmenting a web application into several modules or individual functions and implementing them independently. This independence allows teams to work on their components without depending on others and stops tight coupling.
Easier maintenance and testing
As micro-frontends reduce duplication across applications, they are easier to maintain long term when changes need to be made. They allow developers to work with smaller and more manageable apps, which reduces testing time.
More efficient performance
To load all elements of a page, traditional web development frequently needs several requests. This may not be efficient if some parts are not required for rendering some pages. To improve performance, it is possible to postpone loading these additional modules until they are needed by using micro-frontends. At the same time, using micro-frontends increases fault tolerance since the system is not ruined when one of the components fails.
Connection to backend
The host app allows connection to the backend as it can provide a set of capabilities that the component apps can use. This is another advantage of the micro-frontend's architecture since it is possible, for example, to handle backend streams to provide live data.
Principles that should be followed when using micro-frontends in UI development:
- One host app for multiple component apps;
- Minimal dependency: development, infrastructure and deployment processes are independent. There are only dependencies in the runtime, which is inevitable if the apps need to communicate with each other;
- The host app is a distinct, standalone app that orchestrates its children, so it should be built and maintained independently. Only standard tools should be used so that developer churn does not affect maintenance long term;
- The team creating the component (children) app should be free to use any setup and/or framework technology they choose, entirely independent from the host app;
- Component apps should be allowed to use their framework version and not depend on the host version;
- To integrate apps in the frontend without having to go through backend for simple communications, a message-based communication mechanism needs to be implemented between the host and the component apps.
Micro-frontend using iFrames
iFrames (Inline Frames) are an HTML element that allows embedding one HTML document within another. This structure enables the display of multiple applications or content within a single browser window, effectively creating a page composed of distinct, self-contained sub-pages. Each sub-page can be independently managed, often by different teams or technologies, making iFrames an ideal solution for micro-frontend architectures.
At Flutter, we've determined that iFrames meet all the critical technical requirements for implementing micro-frontends. They are a well-established solution, with their native technology operating independently from component apps. The integration via the Window Messaging Web API ensures minimal dependencies, allowing for flexibility and ease of transition should we choose to adopt a different solution in the future.
How are the host app and its child applications integrated?
It is required a configuration file with child app definitions determining their URL to load the child app bundles into iFrames. The micro-frontend lifecycle is a strategy for negotiating child apps mounting onto the main window for actual use. It is the cycle any micro-frontend component app needs to undergo during its life inside the micro-frontend host to be properly integrated into it. This is a standard protocol that all component apps need to obey, and the host needs to honour. The host app first renders an iFrame that loads the child app in a 3-step protocol that leverages the inter-app messaging system:
- The child app (running in its iFrame) messages the host to inform it is now mounting.
- The host app replies with authentication/authorisation data.
- Based on the auth/auth data it received, the child app replies with:
a) Mounted: the child app is now part of the micro-frontend app and can be used.
b) Unmounted: the child app refuses to mount, and it is expelled from the host.
Implementation status
At Flutter, we're currently in the experimentation and learning phase of implementing micro-frontends. This approach, which involves breaking down large, monolithic frontends into smaller, self-contained components, holds great potential for improving the scalability, flexibility, and maintainability of our applications. During this phase, we're exploring how best to structure and integrate these independent components, ensuring they communicate effectively through APIs and work seamlessly across various technologies and frameworks.
Once we've refined our approach and identified the optimal strategies for our teams, we’re excited to leverage the full benefits of micro-frontends—accelerating development, enabling more efficient collaboration, and ultimately creating a more agile and robust frontend architecture.