Our journey with micro-frontends

Naim Gkamperlo
tech-gwi
Published in
5 min readJun 27, 2022

It was 2019 when our journey started with micro-frontends (or simply MFEs) in GWI. No one in our team had used MFEs in a production environment and the community was just starting its baby steps around them. Our framework of choice was single-spa for our kernel/shell/platform that glues everything app.

Why MFEs though?

At that point, GWI had been developing applications using Elm and React. In order to:

  • Be able to scale our codebase easily without depending on ‘hacks’ to make everything work properly between the two worlds (of Elm and React).
  • A single team can be the owner of a specific MFE which makes the teams all the more autonomous.
  • The risk of using a single new FE technology can be contained within a single MFE and not spread in the whole application.
  • Having separate deployments helped us establish a cadence of deployments for each team regardless of what the other teams do/deploy.

Issues we have faced so far

Instead of analysing all the benefits, I would rather list all the issues we faced so far using MFEs

MFE versioning

At the very start of our journey a great problem surfaced:

How to update an MFE to a new version and make kernel/shell/platform that glues everything aware of its latest version?

The problem

  • We did not need fully automated updates of our MFEs as it could add the wrong versions in the production environment.
  • We did not want a fully manual solution by having to make a git commit to just update a single MFE.

The solution

  1. Create a service (which we eventually called frontend configuration) that depends on absolutely nothing and provides the kernel with the latest version of all MFEs
  2. A simple UI that adds a new version of an MFE and directly updates all the clients with the latest version
  3. The only thing kernel has to do is make a web request to the frontend configuration API to get the latest version of all MFEs every time the application starts

Single design system

Currently, there is not one design system in place, but instead, we have two implementations

  • one for the React-based MFEs
  • one for the Elm-based MFEs

The above causes the following issues:

  1. Hard to detect UI mismatches between the applications and simple UI components
  2. Changes made to the design system are not bubbling up directly to all the MFEs but only in the “Elm” or “React” world
  3. A huge effort of updating UI libraries (e.g material UI from version 4 to 5 used in React world) needs to be propagated to the Elm environment due to web component dependencies ( see down below )
    So far we have not found a good enough solution for the issue above.

Common UI components with logic — Web components

Soon after the first React-based MFEs were deployed in production, we also had some Elm-based MFEs in our development pipelines.
The problem at that point was that MFE had common pieces of functionality needed regardless of the technology used to develop them.
Instead of implementing common functionality twice in Elm and React-based MFEs, we decided to:

1. have such functionality implemented only once either in React or in Elm and finally wrap the output down to web components to be used by both technologies.

2. make communication with each MFE by utilizing browser custom events.
In addition, the web components described above are stored in an internal storybook so that everyone ( from dev to pm to designer and back) can take a quick look/review, etc.

Creating a single-page mini app

Soon after we started our first MFEs another issue was surfaced: there was a need to create a single-page mini-app which was:

  1. too small for a new MFE and at the same time
  2. too big for a web component
  3. able to capture full viewport of the browser

solution #1 — BlackBox pattern
Our first approach was to create a black-box app that communicates with other applications only using custom events and renders and hides from the DOM as needed.
More info on this approach along with the rationale can be found here.
In addition, we have created a guide on creating an MFE BlackBox with React here.

solution #2 — web component with its git repository
Unfortunately, solution #1 was not enough mainly because of patterns already used in the Elm-based apps. In more detail, Elm communicated with the browser using web components and since already implemented quite a few of them as stated above, we needed to use the same pattern in our single-page mini-apps.
Thus, we decided to switch everything to `web components` regardless of the size of the common components created.

MFE communication

For 2.5 years our application managed to exist with minimal interaction between MFEs. In general, communication between MFEs comes with friction and isn’t that straight forward. Module federation was introduced with Webpack 5 as an attempt to make communication between MFEs easier along with other enhancements. This video demonstrates a great way to handle MFE communication using module federation.

Although we are not there yet regarding module federation ( but actively looking into it ) there were certain needs for inter-app communication in our application which made it impossible to keep on neglecting that feature.
Currently, we try to tackle the communication by having a shared state between MFEs which is framework and library agnostic, and probably we will share the teachings of that approach in our next blog posts.

Final words

We still revisit our options and try to use the latest technologies that make sense in our context. Our focus for the near future is:

  • module federation
  • updating fe-configuration with enhanced versioning functionality
  • better React <-> Elm interoperability
  • storybook for the UI components without logic
  • autogeneration of API contracts in typescript interfaces/types

Stay tuned for blog posts that make an in-depth analysis on all of the above and more :)

Resources

--

--