Background
I'm trying to come up with an approach to building microfrontends.
Here are the facts of my circumstance:
- Team 1: Develops the shell web app called "ShellApp" that will embed (host) other microfrontends
- Team 2: Develops a microfrontend web app called "ChildApp" that will be embedded onto "ShellApp"
- Both teams may choose their own web framework independently
- Both teams are independent and must independently deploy their application
- If both teams need to integrate, they need to come up with a contract for their integration points
- There are other microfrontends that will be introduced later.
- The microfrontends to be embedded will have their own routing and are expected to have their own complexity beyond simple components because they are real apps on their own and could really stand alone.
iframe approach
The old-fashioned way of embedding "ChildApp" to "ShellApp" is by using an iframe, and setting up a reverse proxy acting as both proxy for UIs and APIs.
Based on my experience in implementing the iframe approach, the pros and cons are the following.
pros
Cleaner isolation: their respective CSS and JS bundles only affect their own sites because they live on their own document. Parent could not affect the child and vice-versa.
Loosely coupled/contract by URL: parent only needs to know about child app's URLs and not anything about implementation details.
Integration is simpler: if parent want to communicate to its child to show say page2, it will only set the URL to say https://childapp.com/page2.
cons
Heavy: if both shell app and child app shares the same libraries and frameworks, they'll be loaded twice.
Limited integration: changing URLs and listening to its changes can only do so much. But I'm not sure if this is a drawback because having tight integration tends to have the need for implementation details and could potentially be fragile.
Module Federation approach
Then later, I came across module federation which is new to me. The way I understood it is that instead of embedding iframe, you could load a JavaScript module asynchronously that's supposed to insert its contents to the DOM of the shell app.
From what I gathered, here's one article about using Module Federation on MFEs with different frameworks and then he proceeded with workarounds that looks "ugly".
Let's start with the 1st rule for multi framework and multi version micro frontend architectures: Don't do it ;-).
The question
Is module federation the better approach? From how I see it, the following are the caveats.
Tightly coupled/Contract by module: ShellApp now needs to know how to exactly use the component being exposed by ChildApp just like how it would treat any other JavaScript modules.
Obtrusive: all teams have to configure an additional bundler configuration and it has to be webpack.
Leaking implementation details: ShellApp has to know what web framework was used to write the ChildApp. Also, if both ShellApp and ChildApp have routing implemented, they must ensure they work together because technically both ShellApp and ChildApp now live on the same document.
Lacks isolation: because ShellApp and ChildApp live on the same document, their CSS styles need to work in harmony this is even when using Shadow DOM (e.g. background color can still affect the ChildApp. Finally, I was able to try this out myself) I'm not sure if this is really a caveat as it could be a benefit depending on how you see this.