module-federation / core

Module Federation is a concept that allows developers to share code and resources across multiple JavaScript applications
https://module-federation.io/
MIT License
1.31k stars 190 forks source link

External modules not shared #2739

Open althaf101 opened 2 weeks ago

althaf101 commented 2 weeks ago

Describe the bug

Background

My module federation setup has a single host and few remotes. Host loads the commonly used vendor packages like react, react-dom, react-router-dom etc.. from my CDN. For this reason, all these common vendor codes are extenalized in the build process of the host via webpack config option externals.

Expectation

The host is supposed to share these packages with remotes, since we have enabled sharing via module federation config.

Reality

But, upon loading the remotes, what I can see is that remotes are bringing its own set of vendor packages or in other words the host's vendor packages are not shared with remote. There is no version conflict warnings from module federation and all these are marked as singletons too.

RCA

Upon digging into module federation source code, I saw that we are iterating over modules from normalModuleFactory inside the ProvideSharedPlugin [here] and this will cause all the externalized packages to get filtered out since normalModuleFactory will not have them and this is why sharing of the externalized packages is not working with module federation.

Currently, I am patching this by executing the below piece of code forcefully for extenalized modules too

compiler.hooks.finishMake.tapPromise("ProvideSharedPlugin", compilation => {
  const resolvedProvideMap = compilationData.get(compilation);
  if (!resolvedProvideMap) return Promise.resolve();
  return Promise.all(
  Array.from(
    resolvedProvideMap,
    ([resource, { config, version }]) =>
    new Promise((resolve, reject) => {
      compilation.addInclude(
        compiler.context,
        new ProvideSharedDependency(
            config.shareScope,
            config.shareKey,
            version || false,
        resource,
        config.eager
        ),
        {
        name: undefined
        },
        err => {
        if (err) return reject(err);
        resolve(null);
        }
      );
       })
     )
  ).then(() => {});
});

Ask

Sharing of extenalized modules should be handled within module federation plugin itself

Reproduction

### Used Package Manager npm ### System Info ```shell System: OS: macOS 14.5 CPU: (8) arm64 Apple M1 Memory: 131.70 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 16.20.2 - ~/.nvm/versions/node/v16.20.2/bin/node npm: 8.19.4 - ~/.nvm/versions/node/v16.20.2/bin/npm Browsers: Chrome: 126.0.6478.127 Safari: 17.5 ``` ### Validations - [X] Read the [docs](https://github.com/module-federation/core). - [X] Read the [common issues list](https://github.com/module-federation/core/issues). - [X] Check that there isn't [already an issue](https://github.com/module-federation/core/issues) that reports the same bug to avoid creating a duplicate. - [X] Make sure this is a Module federation issue and not a framework-specific issue. - [X] The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug.
ScriptedAlchemy commented 2 weeks ago

You can / should use a runtime plugin to handle this. Use the resolveShare hook and you can replace args.resolver on the hook then just make the resolver return window.react etc.

ScriptedAlchemy commented 2 weeks ago

https://github.com/module-federation/module-federation-examples/blob/master/runtime-plugins/control-sharing/control-share.ts

althaf101 commented 2 weeks ago

@ScriptedAlchemy

At-least for the moment, we are actually locked into the builtin package that comes with webpack. Can't yet switch to the independent @module-federation/enhanced package. In this case,

  1. Is there any side-effects / issues that you see with the current fix that I have applied ?
  2. Is there a better fix available than the current one that I have applied ?
ScriptedAlchemy commented 2 weeks ago

No fix that i know of.

Im not sure what side effects tapping the hook twice will have. It might repeat code in your runtime

If it works, then run with it till it doesn't.