How does module federation choose which dependency version to use?
Asked Answered
P

2

11

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?

Portend answered 8/1, 2021 at 18:9 Comment(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).Undersexed
I had the exact same issue (both host and remote use same version, but remote gets downloaded)Lorraine
D
8

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.

Diver answered 21/2, 2021 at 2:1 Comment(7)
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.Undersexed
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 parallelDiver
@DanielTabuenca does that mean shared deps. will always be downloaded no matter if it already exists(same version) with host ?Volnay
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"Portend
@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.Diver
In an MFE architecture using module federation, what happens when you need to update a major version of a package that needs to be a singleton, like react and react-dom? Of course, the MFE won't be able to do it at the same time.Hippie
@Daniel Tabuenca : Very nice explanation. But is there some typo in the answer? I mean where you say"If the host was sharing module-a:1.0.1" BUT then you say "module-a:1.0.0 from the host"....Should it say module-a:1.0.1 from the host ?Hyperdulia
I
6

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

Icaria answered 18/1, 2021 at 2:30 Comment(2)
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?Portend
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.Diver

© 2022 - 2024 — McMap. All rights reserved.