Cross micro frontends communication

How to communicate between multiple applications

Luis Takahashi
iFood Engineering
6 min readJan 28, 2021

--

In this article, I’m going to explain some ways to communicate between multiple applications and a particular way that I have chosen to use in my current project and work.

If you are not familiar with the micro frontends concept and architectures I suggest you take a look at these amazing articles:

There are several reasons for choosing a micro frontend architecture: maybe your app has grown too much, or new teams are coding on the same repo/codebase, but one of the most common use cases is the decoupled logic of certain domain of an App.

Following this logic, good architecture is one in which micro frontends are decoupled and do not need to frequently communicate but there are some things that micro frontends might share or communicate like functions, components, some logic, or state.

Sharing code

Js Packages Cartoon

For functions, components and common logics could be placed on a third package and imported on each app.

And for creating a package there are several approaches I won’t dive deep into it, but I’ll leave you some examples:

Sharing state

But what about a shared state? Why would someone need to share state between multiple apps?

Let’s use a real-world example, imagine this e-commerce:

Each square represents a micro frontend with a specific domain or functionality and could be using any framework.

Adding some content we notice some parts of the app that might need to share some data or state like:

  • Both item detail and suggested items might need to communicate and inform the cart when an item has been added;
  • The suggested items could use the current items in the cart to suggest another item based on some complex algorithms;
  • Item detail could show a message when the current item is already on the cart.

“If two micro frontends are frequently passing state between each other, consider merging them. The disadvantages of micro frontends are enhanced when your micro frontends are not isolated modules”. This quote from single-spa fantastic docs, maybe the suggested items could be merged with item detail but what if they need to be indifferent apps?

Well for those use cases I have tried 5 different modes:

  1. Web Workers
  2. Props and callbacks
  3. Custom Events
  4. Pub-Sub library(windowed-observable)
  5. Custom implementation

Comparison table

  • ✅ 1st-class, built-in, and simple
  • 💛 Good but could be better
  • 🔶 Tricky and easy to mess up
  • 🛑 Complex and difficult

Web Workers

I have created an example to illustrate a simple communication between two micro frontends with a dummy web worker using workerize-loader and create-micro-react-app also known as crma to setup the react micro frontends.

This example is a monorepo with 2 micro frontends, 1 container app, and a shared library exposing the worker.

Worker 📦

Container app

The container app is sharing the custom worky web worker.

You should be thinking 🤔

But why don’t you import this worky on every micro frontend?

When importing a library from the node_modules and using it in different apps every worker.js will have a different hash after bundled.

So each app will have a different worker since they’re not the same, I’m sharing the same instance using the window but there are different approaches.

Micro frontend 1

Micro frontend 2

Pros ✅

  • According to MDN The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.

Cons ❌

  • Complex setup
  • Verbose API
  • Difficult to share the same worker between multiple micro frontends without using a window

Props and callbacks

When using react components you could always lift the state using props and callbacks, and this is an awesome approach to share small interactions between micro frontends.

I have created an example to illustrate a simple communication between two micro frontends using crma to set up the react micro frontends.

This example is a monorepo with 2 micro frontends and one container app.

Container app

I have lifted up the state to the container app and passed messages as a prop and handleNewMessage as a callback.

Micro frontend 1

Micro frontend 2

Pros ✅

  • Simple API
  • Simple setup
  • Customizable

Cons ❌

  • Difficult to set up when there are multiple frameworks(Vue, angular, react, svelte)
  • Whenever a property changes the whole micro frontend will be rerendered

Custom Events

Using Synthetic events is one of the most common ways to communicate using eventListeners and CustomEvent.

I have created an example to illustrate a simple communication between two micro frontends, this example is a monorepo with 2 micro frontends and 1 container app using crma to set up the react micro frontends.

Micro frontend 1

Micro frontend 2

Pros ✅

  • Simple Setup
  • Customizable
  • Framework agnostic
  • Micro frontends don’t need to know their parents

Cons ❌

  • Verbose custom events API

Windowed observable

In this new era of “micro” services, apps, and frontends there is one thing in common, distributed systems.
And looking at the microservices environment a pretty much popular communication mode is pub/subs queues just like the AWS SQS and SNS services.
Since every micro frontend and the container are at the window, I decided to use the window to hold a global communication using a pub/sub implementation, so I created this library mixing two concerns pub/sub-queues and Observables, called windowed-observable.

Exposing an Observable attached to a topic to publish, retrieve, and listen to new events on its topic.

Common usage:

In this library there are more features like retrieving the latest event published, getting a list with every event, clearing every event, and more!

Using windowed-observable on the same app example:

Micro frontend 1

Micro frontend 2

Feel free to take a look and also use it ❤️

Pros ✅

  • Simple API
  • Simple setup
  • Pretty much customizable
  • Namespace events isolation
  • Extra features to retrieve dispatched events
  • Open-source ❤️

Cons ❌

Custom implementation

After all of these examples, you could also merge some of them and create your custom implementation, using your abstractions encapsulating your app needs, but these options could be tricky and easy to mess up.

Conclusion

There is no perfect or best solution, my suggestion is to avoid hasty abstractions and tries to use the simplest solution like props and callbacks if it does not suit your needs try the other one until it feels good!

You can dive deep into those examples in this repository.

Comment below which one you prefer and why 🚀

This article was originally published at dev.to

--

--