Micro front-end (MFE) is all the buzz right now. it is hot, it’s sexy, and for the most part, is not relevant( MFE is a solution for big projects. it exists to create a separation of concerns). But sadly most posts about MFE are about the initial setup and not about actual production-ready code. How do we communicate between Micro front-ends?
We will separate this into two different types of projects.
Framework agnostic communication
The single thing we can say for certain that is common between all UI frameworks is the window element. This is our “window” of opportunity.
For this example, we will create a custom event (a global function given from the browser)
*const customEvent *= *new *CustomEvent('eventFromMfe', {detail: {name: 'Ryan'}})
“customEvent” event is not fired yet but waiting for whenever we want to fire it.
window.dispatchEvent(*customEvent*);
Now we have fired an event. we do not “expect” a response. sort of a UDP mentality. Somewhere in one of our many many MFEs, we have a passive event listener on the window, waiting for our custom event to be dispatched.
window.addEventListener('eventFromMfe', (customEvent: *CustomEvent*) => {
*const *{detail} = customEvent || {}
console.log('data from custom event', JSON.stringify(detail))
})
We can have multiple listeners in different MFEs waiting for the same events to occur and to run code in response to them.
This is a very manual way of creating the communication between our MFE. we can use a nice library called pubsub-js (pretty well known) which does a similar process but with a more reactive style (I’m pretty sure that behind the scenes it works very similar with the window events, correct me if I’m wrong).
Notes: Using this method allows projects to use different micro-front ends to co-exist with a framework-agnostic mindset. While this works, I hardly believe that a company with a large enough project will use different frameworks. it’s just too complicated to create good inter-team communication.
Communication through the Store (Single type framework)
The store is something we want to be shared between all our Angular MFEs. it gives us access to the store data and more independence of work. We can completely CRUD the store to affect the store data, but we can also “abuse” the way that actions works.
*// MFE1*
*const *globalLoadingAction = createAction('[MFE-Action] Loading', props<{loading: *boolean*}>())
An MFE can dispatch globalLoadingAction events through the store without any reducer or effect needed. It is a sort of a global event, similar to our window.dispatch.
*// MFE2*
*this*.actions$.pipe(
ofType(globalLoadingAction), // only listen to the event
).subscribe((action: Action) => {
*this*.toggleGlobalLoading
})
Our Second MFE, which is connected to the same store, with the help of the singleton instances module-federations gives us, we listen to the relevant actions and handle our logic from within our second MFE. This will cause a more “ping-pong” like communication, but this will give you a very decentralized code base.
Notes:
When using some sort of agreed-upon languages such as actions or an ENUM of custom events we can use an NPM package to deal with this and be shared to all MFE . since each part of our communication is decoupled, package version management becomes a non-issue (for the most part).
Hope this helps :) and will give you the bump you need to explore and test MFEs. for any questions and assistance, you can contact me anytime and i will try to help