question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:5
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
ScriptedAlchemycommented, Sep 5, 2022

I think it should be reopened, this can cause strange regressions where there doesn’t need to be. I believe what would need to change is the SharingRuntimeModule.js

Regarding sharing externals in userspace; something like this might work.

{
  shared: {
    fakeReactKey: {
      import: 'var React',
      import: 'external React',
      import: 'data:text/javascript,module.exports = window.React;',
      shareKey: 'react'
    }
  }
}

But we would need a way to ensure it isnt tree shaken out as being “unused” in the graph.

In the webpack runtime, what we need is something like

register("react", "18.0.0", function() { return React});

1reaction
ScriptedAlchemycommented, Sep 4, 2022

So the problem here. I think, is the remote container initialization phase. If a host marks it as external the runtime should still register react, and just point to the global variable. So the share scope still contains the keys to pass them into remote containers. Otherwise if my remote has import:false set - it crashes because share scope is missing keys, but loadSingleton is still part of the logic

Read more comments on GitHub >

github_iconTop Results From Across the Web

Webpack Module Federation handling when the remote app is ...
I just forked a sandbox, tried it with success when the both modules available. It has 2 modules, app1 as the host, and...
Read more >
Module Federation - webpack
This object is used as a shared scope in the remote container and is filled with the provided modules from a host. It...
Read more >
How to Use Module Federation with Re.Pack 3 | blog {callstack}
Accessing remote JS code exposed by MFE is the key feature of Module Federation and the process is called Runtime Deployment.
Read more >
Faster Builds with Module Federation - Nx
Although Nx hides most of the complexity around Module Federation, ... you need to create implicit dependencies from the host to all the...
Read more >
All things Webpack Module Federation with the Creator himself
We're honored to have Zack Jackson on the Nx Show, the creator of Webpack Module Federation ! Join us for a deep dive...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found