A deep dive into Micro-frontend
Architecture

A deep dive into Micro-frontend Architecture

What & Why Micro-frontends

Recently, the term “Micro-services” has gained significant popularity in the IT industry as it solves many challenges such as decoupling a large and complex application into many small, independent services, better scalability, resiliency, etc.

A micro-frontend is a micro-service that exists within a browser

Building upon the concept of micro-services, micro-frontends emerged in 2016 as a solution to tackle these complexities. As your applications grow, they tend to become bigger, heavier, and harder to maintain and implement new features, making it increasingly sensible to decouple the application into many independent applications for easier maintenance. Adopting micro-frontends can offer several key benefits

Micro-frontend Advantages

Scalability & Single Responsibility

Micro-frontend empowers teams to adapt Domain-Driven Architecture, dividing the application into smaller, self-contained modules that correspond to specific domains. Each team can own specific domains, and build, manage, and implement their own applications. For example, consider an e-commerce site, we will need a page for searching for products, and a page for payment, a page for managing the cart, teams can focus on distinct micro-frontends for product search, cart, and payment functionalities. This division of labor enables teams to work concurrently, implementing new features, fixing bugs, and deploying their features more efficiently. As a result, the overall development process becomes significantly faster, enabling organizations to respond quickly to market demands.


Furthermore, micro-frontends allow teams to take ownership of specific domains within the application. This architecture not only fosters better code organization, maintainability, and accountability but also reduces conflicts and bottlenecks that often happen when many teams work on a monolithic application codebase.

Reliability

Similar to micro-services, micro-frontends offer a high level of reliability due to their independent characteristics. In the case that one micro-frontend encounters an issue or failure, the remaining applications will still continue to operate without any issues. This fault isolation ensures that the failure of one micro-frontend will not cascade the effect to the entire application.

Reusability

Micro-frontends offer reusability across various environments by encouraging the development of modular and independent components, shared design systems, and common utilities. This reusability not only enhances the consistency of user experiences but also reduces efforts to develop the same functions again.

Design and development flexibility

Micro-frontend architecture is not tied to any particular technology stack, it offers multiple teams the freedom to innovate and select preferred tools that are most proficient for developing the application.

Faster deployment

In a monolith application, typically there is only one CI/CD pipeline responsible for building and deploying the entire application to production. However, this approach can have several disadvantages, especially when making small changes such as modifying the style of a button or a small component. Whenever the pipeline is triggered, it will re-compile all the files within the application, resulting in a completely new bundle being deployed. This process introduces the following drawbacks:

  • Slow build & deployment time: The compilation of an entire application can be time-consuming, leading to delays in deploying changes to production
  • Can impact significantly on users’s performance: Whenever a new version is deployed, the entire client-side caching has to be invalidated. This forces the client to redownload entire application bundles again.

Micro-frontends offer a more manageable alternative compared to monolith applications. With micro-frontends, each application can have its own dedicated CI/CD process. Therefore, you only need to build and deploy the code that you have changed without impacting other parts of the application. Additionally, since other applications remain unchanged, there is no need to invalidate their cache, resulting in improved performance and a better user experience.


Legacy Application Migration

A legacy application refers to software that is outdated or obsolete, despite still being in use. Such applications often become bottlenecks when it comes to implementing new features or enhancements due to various factors, including technological limitations.

The nature of micro-frontends, with their ability to be built and deployed separately for each component, provides an easier path to migrate old applications, adapt to new technologies, and facilitate application scalability. This approach allows for a gradual modernization of the system, enabling teams to incrementally update and replace outdated components without disrupting the entire application. By leveraging micro-frontends, organizations can effectively overcome the challenges posed by legacy applications and embrace the benefits of modern development practices and technologies.


Micro-frontend Disadvantages

Challenges in defining micro-frontends

Similar to micro-services, careful consideration is required when determining how to divide your application into multiple micro-frontends. If the micro-frontends are too small, it can lead to excessive fragmentation, resulting in the management of numerous applications over time. Conversely, if the micro-frontends are too large, they become tightly coupled, undermining the benefits of using micro-frontends.

Another aspect to consider when defining micro-frontends is cross-application communication. If applications need to communicate with each other too frequently, it can lead to excessive coupling and negate the advantages of micro-frontends.

Payload size

Duplication of code between micro-frontends can result in a large application payload. For example, if different micro-frontends use different versions of a library like React (e.g., version 16.0.0 in Application A and version 18 in Application B), it forces the client to download multiple versions of the same library, increasing the payload size. While there are approaches to optimize this by prompting the browser to download shared dependencies only once, it is crucial to acknowledge the potential for conflicting dependencies, which can result in unexpected and erroneous behaviors.

Cost

One drawback of micro-frontends is the associated cost. More micro-frontends mean more repositories, CI/CD pipelines, servers, domains, and so on. This leads to higher infrastructure costs as well as increased maintenance efforts.

Team Coordination

Although micro-frontends can be developed and deployed independently, effective coordination and communication between multiple teams are still necessary, particularly when changes to one micro-frontend can impact others. Ensuring consistent collaboration among teams becomes crucial to avoiding conflicts and maintaining a cohesive user experience.

How does micro-frontend work

Build-time integration vs. Run-time integration

Build-time integration is a traditional approach to code sharing, where libraries are installed from npm and reused across an application. However, this approach presents a significant challenge: all dependencies end up in the application bundles, causing the app size to grow with each new dependency introduced.


Consider the scenario depicted in the above image, where Team B makes changes to Package B, and Team D needs to deploy the updated version to production. This process involves multiple steps:

  • Team B builds and publishes the updated package to the Package Registry.
  • Team D updates the version of Package A to the latest one.
  • Team D rebuilds and deploys the new bundle to production.

On the other hand, run-time integration offers a more efficient method of sharing code and functionality. With run-time integration, each micro-frontend can be built and deployed independently. Typically, a host application is responsible for rendering remote applications by downloading their bundles at runtime as needed. There are three types of compositions:

  • Server-Side Composition
  • Edge-Side Composition
  • Client-Side Composition

Server-Side Composition

When a client requests to specific URL, there will be a service or backend that sits between browser and the actual applications, which is responsible for combining and rendering multiple fragments, or micro-frontends into a complete HTML page before returning it to the client.


Edge-Side Composition

Similar to Server-Side Composition but in this case, the CDN will take care of the work

Client-Side Composition

Client-side composition involves using scripts on the browser to compose multiple micro-frontends into a single page. This allows you to preload, load, and render parts of the application on demand. For example, when a user first visits the URL home page, only the bundle home.js is downloaded, whenever the user clicks to navigate to the product page, a different bundle product.js will be loaded to the browser. You can preload these bundles for a speed boost as well. A big advantage of this approach compared to Server-Side & Edge-Side Composition is that it doesn’t need to reload the page to render dynamic content.

There are many ways to apply the run-time integration, the simplest approach is composing every application in the host container with an iframe. However, this approach is quite old and there are also many disadvantages. In fact, now we have many better tools, and frameworks to handle this such as Webpack 5 Module Federation, Single Spa, qiankun, etc.

Module Federation as a game-changer

Module Federation is an official feature of Webpack that enables the dynamic loading of modules from multiple independent build systems.

The core concept of Module Federation revolves around distinguishing between local and remote modules. Local modules refer to the modules within your application, while remote modules are external modules that your application needs to utilize. These remote modules are loaded at runtime, allowing for flexible and efficient module sharing across different build systems. This introduces significant improvements and capabilities to web development, especially in the context of micro-frontend architecture.


Alternatives to Module Federation

In addition to Module Federation, there are several frameworks and libraries available that facilitate the development of micro-frontends. Some notable options include SystemJS, Single SPA, and qiankun.

These frameworks have proven stability and offer numerous out-of-the-box features to support micro-frontend development. However, it is important to consider that adopting these frameworks may result in your applications being tightly coupled to a specific framework. On the other hand, Module Federation differs in that it is not a framework itself; rather, it is a plugin integrated into Webpack. This distinction provides greater flexibility, allowing you to choose the build tool that best suits your needs.

By leveraging Module Federation, you can enjoy the benefits of code sharing and dynamic module loading while maintaining the freedom to select the development environment that aligns with your preferences and requirements. This flexibility empowers you to integrate Module Federation seamlessly into your existing development workflow without being tied to a particular framework. All in all, each alternative has its own unique strengths and considerations. Evaluating the specific requirements and constraints of your project will help determine which approach is the most suitable fit.

Conclusion

Front-end development has undergone significant evolution and complexity in recent years, and micro-frontends provide a compelling solution to address the limitations of monolithic architectures.

By breaking down monolithic applications into smaller, independent applications, teams can work autonomously, utilizing their preferred technologies and workflows to deliver features rapidly. This architectural style offers numerous benefits, including enhanced maintainability, reusability, and adaptability to modern web applications and future technologies.

As of the time of writing this article, micro-frontends have reached a stable state, supported by a wide range of technologies and tools that facilitate the development of complex micro-frontends. However, it is essential to know that every architectural approach carries its own set of pros and cons. Micro-frontends, while offering significant advantages, also introduce additional complexity and require meticulous planning, architectural design, and consideration of various aspects. This approach is particularly suitable for large-scale applications or organizations, but it may prove excessive for small and medium-sized applications.

In an upcoming article, we will explore the ease of micro-frontend development using the powerful combination of Module Federation and Vite. Stay tuned for practical insights and examples of building micro-frontends with these cutting-edge technologies.

References

(*) This article was written by Duc Ta - Front-end Software Developer at Home Credit Vietnam

要查看或添加评论,请登录

社区洞察

其他会员也浏览了