30/01/2023

Thinking differently about design – how micro frontends can change the way you see software

The frontend has traditionally followed a monolithic architecture, where a single code base has been maintained for the frontend of an application.

By Mokake Letsie in micro frontend architecture

blog main image

This has been the case even throughout the microservices revolution in the backend. Challenges of this monolithic architecture include too much complexity due to the frontend dealing with too many business functions. Also, too many components lead to difficulty in maintaining the system. Additionally, a single code base makes it difficult to scale the team.The micro frontend architecture, or micro frontends, brings to the fronted, similar benefits to those brought by micro-services to the backend, and then some more. Micro-services split the backend into self-contained, independently deployable APIs, each handling a well-defined responsibility scope.

The following are some of the major benefits that microservices brought to the backend: improved productivity due to a reduced code base per microservice that is developed, deployed, and maintained independently; better resiliency due to errors being easier to find in smaller end-to-end APIs as opposed to in the monolith; and better application and team scalability.

This article discusses some of the basic ideas underlying the micro frontend architecture and highlights the potential benefits that can be gained from following it. Essential elements of a micro frontend architecture: There are three basic elements of a micro frontend architecture: micro frontends, a micro frontend framework, and independently developed and deployed host applications/pages. The term “micro frontend” refers to code for a self-contained portion of a webpage. The code is developed by one team, usually in the context of one of many constituent applications of a larger system, and then it is shared with the other applications for reuse. The originator of a micro-frontend is referred to as a remote application or page.

The question of what size of component constitutes a good micro frontend target is somewhat up for debate, but a general rule is that the component should implement a commonly used or omnipresent view and/or behavior. Host applications/pages are multiple independently developed and deployed applications/pages that incorporate micro frontends that are developed and shared from a remote application/page. Any of the hosts can share micro-frontends of their own, thereby simultaneously assuming remote roles. A micro-frontend framework is a piece of software that handles the dynamic sharing, loading, and unloading of micro-frontends between remotes and hosts. While there are frameworks like that on the market, the unique needs of the proposed system could dictate that a team either augments the off-the-shelf solution or builds its own framework.

How it works:

Independently deployable builds

A complex software system is broken down into multiple smaller applications that can be developed, tested, and deployed independently by multiple independent teams. This allows many people to work on the same system without stepping on each other’s toes.

Sharing of components

One team can implement a component or a function that may be useful to a separate team. A sharing mechanism is put in place to effect dynamic loading and synchronize effective updates of the shared component as it evolves. Approaches to sharing components:

Central npm library

One way to share micro-frontends would be to implement a centralized npm library where reusable components are implemented and to have host teams do a library update to incorporate the latest version of the consumed components when those components get updated. The drawback to this is a lack of synchronization. It may be desirable sometimes to have UI changes take effect immediately on the host applications. This approach, however, requires that the library team first alert every host team about the change, which adds a bit of a delay.

Asset stores

A dedicated team develops the reusable components and builds and stores them in a static server (S3 artifacts). The server is hooked up to a shim library, which connects it to the host applications. The shim library is configured to dynamically inject the most up-to-date versions into the host applications. This solution necessitates extensive DIY and customization, and it is prone to high costs due to context-switching.

Module federation

Module federation creates a direct synchronous run-time link between the remote and host, allowing micro frontends to be shared. It is included with Webpack 5 and can be used with any of the popular view frameworks, including Angular, React, and Vue. Module federation allows for one application to expose reusable components so that another application can load and incorporate them. With module federation, upon updating a shared component, the remote does not need to inform the host of the change because the latest version immediately gets loaded and rendered by the host, provided the API contract remains intact. When sharing a component, it also shares the dependencies for the component, but only those that are not already included in the host page. This reduces the bundle size drastically. There is also the possibility of asynchronous loading so that certain components are loaded only when needed, which also reduces bloat in the runtime.

A potential problem is if a remote developer changes the API contract without alerting a host application team. This can break the host application. However, there is a workaround involving error boundaries that guards against that scenario and ensures safe failure. One can also combine npm libraries and module federation so that instead of rendering an error message, the system falls back to an old npm library version of the affected micro frontend. Module federation allows sharing of more than just components. A remote application can share functions, states, and whole pages. A login state and related functions can be originated from a single application (e.g., a “login” application developed by the “login team”) and be shared at runtime with constituent pages that are deployed separately but are related. Also, SPA routing is easily achievable because of this.

Advantages of micro frontends:

  1. Team scalability: more people can work on one frontend project without stepping on each other’s toes: applications are versioned and independently deployable.
  2. Separating strategic and tactical focus: some teams can focus on long-range deliverables that cater to actual functionality and business functions. Others can focus on tactical aspects, such as tweaking the margins of a reusable UI element to improve aesthetics and make it more engaging to the end user. This setup improves productivity by removing the need for developers to constantly context-switch between strategic and tactical skills.
  3. Sharing and Reusability: micro frontends can be reused on any host page that conforms to the defined standard, thereby reducing duplication of efforts. This also allows for the standardization of the UI and much smaller bundle sizes for the separately deployed micro frontends.
  4. Technology agnosticism: If a host page conforms to the defined micro frontend standard, it does not matter what view framework it is implemented in; it will be able to load and use the micro frontends that were developed using a different framework. (e.g., vanilla
    JavaScript, Solid.js, React) Potential disadvantages of micro frontends:
  5. Complexity: it is by no means an easy architecture to implement. It requires the coordination of independently deployed applications into one cohesive system. This means it is important to design well-defined interfaces to ensure smooth sharing and integration both in the present and as the system evolves.
  6. Unexpected runtime issues: use of micro frontends from remote applications means that someone can make a change in the expected context for use of a shared reusable component. The change will be discovered in the host app in the form of a run-time error.
    This is likely to occur due to the isolated nature of the team organization. Setting up for or migrating to a micro frontend architecture: The following is a 3-step guide to adopting the micro frontend architecture for a new project or for migrating a previously monolithic frontend to the micro frontend architecture.

 

Look for micro frontend targets: 

Step one is to identify UI/UX elements that can be made into self-contained reusable components (micro frontends) (e.g., panels, headers, footers). There is flexibility in deciding what size of component constitutes a reasonable microfrontend to share.

Define requirements: develop architectural requirements relating to the nature of interactions between remote and host apps or pages. This includes the API contracts, elements of the appropriate sharing strategy for components, and the desired behavior.

Evaluate frameworks that are available (or design own DIY framework) to meet the requirements defined in the previous step: There are several Micro-frontend frameworks on that market. Evaluate them and pick one that can most closely meet the requirements defined above. An entirely custom framework could be necessary to meet the requirements. However, it might be a good idea to use the third-party framework as a starting point and customize some of the behavior to better address the more peculiar requirements of the proposed system. Some micro frontend frameworks are available in the market.

Below is a list of some of the micro frontend frameworks available in the market, many of which are open source:

  • OpenComponents: (https://opencomponents.github.io/)
  • Piral: A react-based MFE framework (https://piral.io/)
  • Single-SPA: simplifies the integration of different view frameworks in a system. (https://single-spa.js.org/)
  • Luigi: (https://luigi-project.io/)

Get Started With Full Stack!

Ready to transform your business? Contact us today to discuss your project needs and goals.