The Secret Sauce of Micro Frontends: Doing it by the books

Excerpts from the Open MRS RFC by the Micro Frontend SQUAD.

Faizal Vasaya
Globant
8 min readOct 7, 2020

--

Calculated decisions for architecting Micro Frontends
Calculated decisions for architecting Micro Frontends

The Need for a Micro Frontends Rule book

It was one fine day when we were on a pursuit to research on well-established standards around Micro Frontends. One of the major reasons for the research was to lay down a foundation layer for our future work in order to create a complete, stable, civilized and production-ready Micro Frontends ecosystem.

After a couple of hits and misses, we landed on one of the RFCs on Micro Frontends curated by the OpenMRS team. Reading it thoroughly helped us realize that this is exactly what the doctor ordered and hence, we decided to reuse the efforts of the OpenMRS Micro Frontends SQUAD rather than reinventing the wheel. This is also because the squad has been using the openmrs-frontend-rfc for all their decisions that led to the stability of the current Open MRS Micro Frontends ecosystem.

Yes, that is the meat of the matter for this article. Welcome yourself to a journey that would not only help you digest the current Open MRS frontends RFC but also enable you to map your needs to a Micro Frontends architecture that is stable and well-defined at its roots by following the best practices.

Believe me, this isn’t a one time read, use it as a point of reference whenever you’re in a meeting room, brushing your brains around one of the most common questions related to Micro Frontends such as:

  • How do we architect a Micro Frontends ecosystem?
  • What are the different building blocks that are required to set up a Micro Frontends ecosystem?
  • How do you scale your frontend teams in a web application that has circular connection points?
  • How do you deploy Micro Frontends?
  • Any many more…

Hope you’re all fired up and ready with your guns blazing to exercise your brain cells. Let’s break a leg.

Unfurling it one page at a time

Let’s explore the key points to look into while architecting a Micro Frontends ecosystem and how we adopted them. Just in case you reached here and aren’t aware of what on earth Micro Frontends are, here’s an amazing explanation by Joel Denning. Let’s continue.

Rule I: Single Page Application (SPA)

Each Micro Frontend in the ecosystem should itself be a Single Page Application. The benefit of this would be a seamless user experience as the browser would be responsible to render the DOM as per the instructions mentioned in the JavaScript. Also, the routing and navigation of the web application would be handled at the client-side hence avoiding server round trips to get the DOM for a given route.

Such a SPA for a Micro Frontends ecosystem could easily be created using either Angular, ReactJS, Vue or Svelte.

Implementation Challenge

Multiple Angular Applications
Multiple Angular Applications

Challenge 1

Let’s consider a scenario where we need to load a couple of Angular applications on a single page such that the user gets a seamless user experience without a round trip to the server to render DOM elements in the browser.

angular-application-1 loaded as a Micro Frontend
angular-application-1 loaded as a Micro Frontend

Challenge 2

Apart from that, an Angular application, let’s say ‘angular-application-1’ has its own navigation interface which allows the user to browse ‘angular-application-1’ independently.

angular-application-1 has its own route /users
angular-application-1 has its own route /users

Challenge 3

Also, as soon as the user navigates to a given route, let’s say ‘/users’, it should be loaded by ‘angular-application-1’ again without any server roundtrips to render the DOM.

A Possible Solution

The above implementation challenges could very well be resolved using single-spa which is considered to be one of the best solutions to set up a Micro Frontends ecosystem. Its CLI provides an application called as root-config which uses single-spa library to register Micro Frontends. This is what would help us solve Challenge 1. On the other side, Challenge 2 and Challenge 3 could be resolved by creating Angular Micro Frontends as per the single-spa norms and using the routing library provided by the Angular framework.

Rule II: In-browser Modules

In a normal scenario, a compilation of an Angular, React, Vue or Svelte application produces an index.html, static assets such as images and JavaScript files with it paths loaded in the generated index.html. However, based on what we learned in Rule I, the index.html page should only be loaded for the root-config whereas for all the other Micro Frontends only the JavaScript should be loaded which internally defines the DOM that needs to be rendered for a given Micro Frontend. How do we load the JavaScript files generated by the build process of Micro Frontends without rendering the index.html file for each Micro Frontend?

Implementation Challenge

Compiling the ‘root-config’, ‘angular-application-1’ and ‘angular-application-2’ would produce the following output:

The challenge here is to load the main.*.js files of both ‘angular-application-one’ and ‘angular-application-two’ in ‘root-config’ as and when required. By ‘as and when required’ we mean when the user navigates to a route that requires the ‘root-config’ to load a given Micro Frontend.

A Possible Solution

As proposed by the Open MRS front end RFC, an in-browser JavaScript module should be used here which would allow lazy loading of JavaScript code within a container such that it doesn’t expose any variable or logic to the outside world (window) unless explicitly intended. Since JavaScript modules are not supported out of the box by the browsers which is why the use of SystemJS has been proposed so that the in-browser modules mentioned in the import maps could be loaded. In addition to that, we predict that Module federation which has been recently introduced in Webpack 5 is a better alternative as it supports dynamic loading and resolution of dependencies, and controlled customization compared to SystemJS.

Rule III: Import Maps

From the Rule II implementation challenge, it is quite clear that each Micro Frontend at the end is compiled to a JavaScript file. Now, for production deployment, it is quite obvious that these Micro Frontends (JS files) will either be pushed to a blob storage provider such as Google Storage Bucket or on a Content Delivery Network (CDN) provider. A challenge here is that how do we inform SystemJS about the current location of these individual Micro Frontends.

Implementation Challenge

For instance, the Micro Frontends created and built for the challenges in Rule I and Rule II i.e the ‘angular-application-1’ and ‘angular-application-2’ are deployed on Google Storage Bucket. Now, how do we inform SystemJS used in ‘root-config’ about the locations of these Micro Frontends? The solution is import maps.

An import map is a mapping of Micro Frontends to its location. In the below example, an import map is defined stating the name of Micro Frontend and its location.

Try it out

  • Angular with SystemJS, Single-spa and Docker — Hands-on experiments will soon be published

Rule IV: Style Guide with Design Library

With small multiple teams working on different Micro Frontends, it is quite possible for a team to diverge from the branding guidelines and design system defined for a product, leading to inconsistent User Experiences. Hence, the proposal is to create a ‘style-guide’ Micro Frontend that defines the design system that needs to be used across all the Micro Frontends. Design system as in ‘Ant’, ‘Material’ or ‘Bootstrap’ etc which defines the global CSS classes and should be inherited by all the Micro Frontends.

Defining just the design system does not guarantee consistency as the varying behavior of the individual components used across the Micro Frontend ecosystem could confuse the user. For example, for a multi-select dropdown, one team designing a Micro Frontend could opt for chips to show selected options whereas the other team might only opt to show the number of options selected in the dropdown. Now, in order to avoid such inconsistent user experience, reusable components should be added to the style guide and be used across all the Micro Frontends hence eliminating the risk of unsatisfactory user experience.

Wait !! We just talked about reusable components, but how do we decide on which framework should be used to design these reusable components in the style-guide. Should it be built by Angular, ReactJS, Vue or Svelte. The answer is, it depends. If all the Micro Frontends in the ecosystem are built using a single framework, for example, ReactJS, use the same framework to create the style-guide. Whereas, if your Micro Frontend ecosystem is a multi framework ecosystem then these reusable components should be framework agnostic, i.e built with either Web Components or single-spa-parcles. Using web components or single-spa-parcles enables the dev team to create framework-agnostic components that allows those components be used either with an Angular, ReactJS, Vue or Svelte.

Rule V: Utility Module

We did create a centralized location to load all the Global CSS and components that are used across the Micro Frontends, but what about utility methods and shared state of the application that is to be made available to all the Micro Frontends. By utility methods, we mean methods used to perform business calculations, common Enums such as CustomerType and Classes such as Customer which is used in 60% of the Micro Frontends (in a banking application). Should we duplicate the logic for all the Micro Frontends or there has to be a centralized location that could be used to share all the cross-cutting concerns with all the Micro Frontends?

A Possible Solution

Utility modules could be created as in-browser module using single-spa utility module which supports TypeScript out of the box. A redux store could be created in this utility module that enables all the Micro Frontends to share state. Apart from that, logic to authenticate and authorize users could also be shared using the utility module. Moreover, utility modules can also be used to analytics, error reporting and push notifications which are commonly occurring cross-cutting concerns in an application.

What you’ve explored is just the tip of the iceberg. I am in the process of creating hands-on experiments for all the concepts discussed above so that both the architects as well as developers may use this article as an entry gate to the world of Micro Frontends. Feel free to follow, in case you wish to receive updates as these hands on experiments are published.

Happy Coding !!

Suggested Readings

  • Do you know we can share dependencies between Micro Frontends to reduce the final bundle size, here’s how you do it.

--

--

Faizal Vasaya
Globant

Technical Lead | Full-stack JS developer | Ethereum, Web 3.0, Solidity and Blockchain developer | GCP 1x