5

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

  1. 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.

  2. Loosely coupled/contract by URL: parent only needs to know about child app's URLs and not anything about implementation details.

  3. 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

  1. Heavy: if both shell app and child app shares the same libraries and frameworks, they'll be loaded twice.

  2. 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.

  1. 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.

  2. Obtrusive: all teams have to configure an additional bundler configuration and it has to be webpack.

  3. 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.

  4. 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.

1
  • I don't see an easy answer there. But will note that I have seen quite a few browser specific bugs working with iFrames particularly on Safari and iOS WkWebView.
    – joshp
    Jul 4, 2021 at 22:35

1 Answer 1

5

Be aware that Module Federation is not the full solution. It just handles dynamic loading of JS files and that you can define dependencies that should be used multiple times (instead of get loaded multiple times).

But you can implement the childs as WebComponents.

If your ChildApp is implemented as a WebComponent, then your ShellApp only has to know the interface. Because then the "child" is looking just like a regular HTML element.

And the ShellApp does not have to know anything about the child implementation details, like which framework was used.

Still, if you want to make use of the feature of not loading dependencies twice (like Angular 11 for child1 and a second Angular 11 for child 2), then you need to follow the Webpack Module Federation rules. And that means that the childs have to at least know that Webpack MF will come into play.

7
  • Thanks to this, this seems to be a good starting point. Started doing this and I'm getting several errors because Angular seems to be expecting zone.js and additional settings to be set like APP_BASE_HREF. It kinda feel forced and not straight-forward. Jul 5, 2021 at 8:35
  • 1
    The Angular team implemented the WebComponents API under the name "Angular Elements". Perhaps take a look at the documentation angular.io/guide/elements for more details.
    – JanRecker
    Jul 5, 2021 at 9:02
  • Thanks JanRecker, I was able to make it work at least. I've added another caveat to my list as I realized things don't go well in terms of styles. Shadow DOM as form of isolation can only do so much. Jul 5, 2021 at 18:36
  • The shadow dom should be near 100% isolated. I know only one way to interfere with the styling in the shadow dom. If you have css variables defined in the shadow dom and define the same ones in the regular dom. Then the parent values will overwrite the ones in the shadow. Thats a wanted behavior, it allows to make the styling configurable. What exactly is the problem in your case?
    – JanRecker
    Jul 6, 2021 at 9:03
  • That sounds reasonable for microfrontends owned by the same team. Otherwise, the child app and parent app has to know each other in order to know the side effects. This creates uncertainty to both teams and they now have to be conscious about their styles. Of course it can be fixed but it involves collaboration which reduces the independence of each team which defeats the primary point of microservices and microfrontends. Routing is another problem too, unfortunately. Jul 6, 2021 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.