Reputation: 9464
Unfortunately, my repro for this is in a complex proprietary project, so I will do my best to explain what is going on.
The closest example project to my use-case is this one: https://github.com/module-federation/module-federation-examples/tree/master/dynamic-system-host Essentially, I have an omnidirectional setup where a single Shell App consumes a set of Remote Apps. Remote Apps are discovered during runtime, and are hence not specified in the Webpack config.
The Shell, as well as all Remotes, have a dependency on a shared library, my-shared-lib:
"dependencies": {
"my-shared-lib": "^1.0.0"
}
The Shell, in its Webpack config, exposes this lib as an eager singleton:
new ModuleFederationPlugin({
name: 'shell',
filename: 'shellDefinition.js',
shared: {
'my-shared-lib': { singleton: true, eager: true, requiredVersion: '^1.0.0' }
},
}),
The Remotes, in their configs, also have it as shared, but not eagerly:
new ModuleFederationPlugin({
name: 'remoteNameHere',
filename: 'remoteDefinition.js',
exposes: {
'./app': path.join(modulePath, 'app.js'),
},
shared: {
'my-shared-lib': { singleton: true, eager: false, requiredVersion: '^1.0.0' }
},
})
The problem is this: I have verified both by runtime debugging and inspecting the bundles generated by Webpack that this lib is being included and instantiated several times - once for the shell, and once for each remote. The code for the lib is even present in the bundle for the Remote which Webpack loads when fetching the exposed ./app.js.
I am at a loss for understanding what is going on here. I have tried to also share every single dependency of my-shared-lib, but this does not help.
My expectation would be that the Remotes use the instance of my-shared-lib which is shared by the Shell, rather than creating their own instances.
Have I completely misunderstood how dependency sharing works, or am I doing something else wrong?
It should be noted that both the Shell and the Remots all have single entry points.
Upvotes: 9
Views: 8485
Reputation: 81
To figure out what goes wrong with your shared you can use undocumented webpack's feature. In your shell app use this code while initing your app:
window.sharedScope = __webpack_require__.S.default;
Then in realtime go to console and look into sharedScope variable (in global scope).
You will see all your shared modules with their versions and source microfrontends. It'll help you to debug your problem.
Also ensure that your shared lib is not bundled into the remoteEntry or (if it is so) check 'eager' option, it should be set to false for remote app and true for shell (or you should check if it is loaded by hands before loading remote app).
Upvotes: 0
Reputation: 11
for your remotes webpack Module Federation configurations try removing the singleton option (having it set in both configs may be the problem, you want only one app to initialise the singleton) and eager option (I think it is false by default, this option tells to load the dependency before checking for shared ones, so you use it mainly on containers app). That's what I do on my configs (multiple remotes) and it seems to work well:
new ModuleFederationPlugin({
name: 'remoteNameHere',
filename: 'remoteDefinition.js',
exposes: {
'./app': path.join(modulePath, 'app.js'),
},
shared: {
'my-shared-lib': { requiredVersion: '^1.0.0' }
},
})
PS (we never know): You may have problems with tree shacked libraries when using module federation, it downloads all the whole library when putting them on shared.
Upvotes: 0