12

I've been playing around with this module federation example, where the setup is relatively straightforward - a host is consuming a module from a remote with a shared react dependency. When running this locally, I noticed that despite both host and remote having the same react/react-dom versions, the remote's version is always the one downloaded.

Based on my research it seems that module federation will pick the "best" version of shared dependencies, but I'm surprised that the remote one will be chosen in a case where both have the same version. How is this decision made? Is there a way to force the host's version to be used in this case?

2
  • Did you ever figure this out? Our team is encountering the exact same issue (both host and remote use same version, but remote gets downloaded). Commented May 2, 2022 at 16:10
  • I had the exact same issue (both host and remote use same version, but remote gets downloaded) Commented Jul 11, 2022 at 7:04

3 Answers 3

9

Basically, when your host starts up it will register all the versions it has into the shared scope. Every time you load a remoteEntry.js from a remote, the remote will also add their versions to this same scope, but only if that exact version does not exist already.

So for example, if the host shares module-a at version 1.0.0. When the host loads it will put module-a:1.0.0 into the shared context. If the remote also shares module-a:1.0.0 it will not put it in the context, because it is already there. If the host was sharing module-a:1.0.1 then the context will now have two versions: the module-a:1.0.0 from the host and module-a:1.0.1 from the remote.

At this point we are just talking about registration... we haven't chosen which version to use, but we are registering all unique versions shared from all remotes and hosts. And basically the first to register it wins.

Now when the version resolution algorithm runs... it will figure out based on all the requirements which version to use. If the algorithm chooses version 1.0.0 of the module, then it will go to the scope and use whatever module is assigned to version 1.0.0 which in this case would be the one from the host, because the host ran first and was able to register it first. If the algorithm picked 1.0.1 it would use the module from the remote. If multiple remotes provided 1.0.1 then it will use the one from the remote that first registered it into the scope.

Sign up to request clarification or add additional context in comments.

7 Comments

So, Niko says: "I'm using the same version for both host and remote, but remote gets used". Daniel says: "When both host and remote use the same version, remote will get used because it gets loaded first.". So, Daniel says what Niko says is happening wouldn't happen. For my team, which is seeing the same behavior as Niko, this answer doesn't help.
It may not be deterministic which one gets used, but it shouldn't matter if they are both the same exact versions. The one that will get used is whichever remoteEntry.js script got loaded first. Since things can load in parallel
@DanielTabuenca does that mean shared deps. will always be downloaded no matter if it already exists(same version) with host ?
Had some extra time to look into this today - it looks like part of this answer is incorrect - If you look here, nstead of being "first to register wins", it is actually the "greatest app name by string comparison" that wins. If you change the name of app1 to app3, then its version will deterministically be used because "app3" > "app2" but if you leave it as-is in the example, then app2 will be used because "app2" > "app1"
@RohitGarg no the only thing that is initially loaded from all the remotes is the remoteEntry.js which only has a manifest not the actual sripts. Dependencies will get loaded from individual remotes once federation determines where to get it from. It's important to split dependencies right though, otherwise there is a chance of loading something twice since the dependency may exist within a larger bundle.
|
6

This article explains the mechanism very well. https://www.angulararchitects.io/en/aktuelles/getting-out-of-version-mismatch-hell-with-module-federation/

2 Comments

That's a great resource! I don't think it explains my question specifically, though. In an example where the host and remote had the same version of a dependency, why does it choose to use the remote version instead of the host version?
IT choses to use whichever one managed to register first. The registrations happen through the included remoteEntry.js files during an asynchronous step in which they may all load in parallel. From the point of view of the browser, they are all remote.
0

Based on my analysis on webpack code generation, few points to note are

  1. A dependency which is not loaded eagerly by the host can be replaced with any other remote mfe with eager:true
  2. A dependency which is not loaded eagerly by the host can be replaced with any other remote mfe with eager:false, if the unique name of the remote is greater than that of the host
  3. A dependency which is loaded eagerly by the host can still be replaced with any other remote mfe with eager:true if its not been consumed yet.

At the end, in all the case its important to know that it doesnt matter which mfe's dependency is getting registered, important is that the dependency is provided when its needed to avoid any eager consumption error

So, in this case, you are right the longest unique app name wins

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.