Skip to content

Module Federation: unable to share externalized dependency between host and remote #15554

Description

@lubieowoce

Bug report

TLDR: ModuleFederationPlugin won't expose a host's dependency to a remote if the dependency is an external.
To be honest, I'm not completely sure if this is a bug, a missing feature, or just a technical limitation of ModuleFederationPlugin... but i'd like to be able to do that 😄

NOTE: i'm using React as an example, but this behavior occurs regardless of what library i'm trying to externalize+share.


Context

Our module federation setup is pretty standard (except for the externals, apparently). We've got two apps:

(Host)           (Remote)
SomePage  ---->  SomeWidget

Both of these are React apps, with React stuff shared via a typical ModuleFederationPlugin config:

shared: {
  'react': { singleton: true },
  'react-dom': { singleton: true }
}

This all works fine.

Now, we'd like SomePage to get React from a CDN link, so we tried externalizing it in SomePage via a typical

externals: {
  'react': 'SomeGlobalVar',
  'react-dom': 'AnotherGlobalVar',
}

the idea being that React would get wired up everywhere like this:

Script tag  <script src="/our-cdn/react-stuff.js>
      |
      |
      |   webpack `external` (global var)
      |
      v
SomePage (Host app)
      |
      |
      |    ModuleFederationPlugin's `shared` exposes React
      |
      v
SomeWidget (Remote component)

What is the current behavior?

Unfortunately, despite SomePage successfully loading React from the CDN, this doesn't work.
The externalized React doesn't end up getting get shared between SomePage and SomeWidget, so we get two copies of React in one tree, which leads to a crash for the usual reasons. From my testing, it appears that despite the ModuleFederationPlugin config, SomePage never puts React into the shared WMF scope, so SomeWidget understandably loads its fallback. The versions are the same between both, and removing them doesn't change anything. I've also tried this with lodash, and that also results in two copies, one from the CDN, and one loaded via SomeWidget's fallback.

What is the expected behavior?

Dependencies should be shared between host and remote even if they're externals, as illustrated in the diagram a few paragraphs up.

Steps to reproduce

I've added some externals to basic-host-remote from module-federation-examples to reproduce this setup:

https://github.com/lubieowoce/module-federation-examples/tree/externals-test/basic-host-remote

the change is very small. You can run it via cd basic-host-remote && yarn && yarn start, then navigating to http://localhost:3001/. It'll flash and then turn blank, because when you when mix two copies of React in the same tree, it'll crash with "Error: Invalid hook call". This demonstrates that the library isn't actually being shared between the host and remote.

Other relevant information:

webpack version: 5.70.0
Node.js version: 14.17.6
Operating System: macOS 11.6, ARM

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    webpack-5Concerns the webpack 5 line

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions