Unfortunately, my repro for this is in a plex 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: 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 pletely 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.
Unfortunately, my repro for this is in a plex 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./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 pletely 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.
Share Improve this question asked Dec 27, 2020 at 15:15 csvancsvan 9,47412 gold badges55 silver badges94 bronze badges 3- What do you mean by included/instantiated for every remote? Are you getting multiple chunks loading from multiple urls? – Daniel Tabuenca Commented Feb 21, 2021 at 2:30
- hey @csvan, did ya ever get figure this out? – stillnoob Commented Jul 21, 2023 at 17:48
- Having the exact same issue, which is pretty surprising if you think about it, module federation's main idea is module sharing - which seems not to be working at all. Unless of course we're missing an elephant like object in front of our eyes... – Johnny Commented Sep 15, 2024 at 9:14
2 Answers
Reset to default 0for 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.
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).