Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Microfrontend does not work on an app with different React versions #559

Open
CerealPlayer opened this issue Jan 8, 2024 · 8 comments

Comments

@CerealPlayer
Copy link

Versions

  • vite-plugin-federation: v1.3.3
  • vite: v5.0.8

Reproduction

Here is a sandobox:
https://codesandbox.io/p/github/CerealPlayer/react-federation/main?file=%2F.codesandbox%2Ftasks.json%3A17%2C23&workspaceId=5db67876-a84e-4ee6-9441-cef04c6a5078

Repo:
https://github.com/CerealPlayer/react-federation

Steps to reproduce

Clone the repo, npm install in the project's root, run npm start to run both apps and click on the button in http://localhost:3000. There's a host app that renders a microfrontend living in the remote app, exposed via Vite Plugin Federation. Both apps run React, except one (the host) is React 17 and the other (the remote) was built with React 18. The remote app's exposed component is wrapped in a Custom Element to try to isolate React in case it is not the same version as the one in the host

What is Expected?

Since both apps use different versions of React, the shared react file from the remote is used instead of the one in the host, so both versions on React can live together. If the versions are the same, it would be expected that the host's react file is the only one in use.

What is actually happening?

Both host and remote react files are downloaded but we see this error.
bug

Which seems to indicate that one of the react copies was not properly generated or the libraries are not properly shared.

Is there something that I'm missing? I would expect that since the remote's custom element calls ReactDOM.createRoot(...).render inside a shadow root, host's react shouldn't be aware of it.

@raffidahmad
Copy link

have you tried setting 'react' & reactdom in the shared property?

@kirill-dev-pro
Copy link

@raffidahmad but what if you dont want to share react version?

@raffidahmad
Copy link

@raffidahmad but what if you dont want to share react version?

it doesn't share them technically, it just ensures the same version is used and also only loads it once rather than twice
try adding react and react-dom in both host and remote, i think that should allow the behaviour you're expecting

@kirill-dev-pro
Copy link

@raffidahmad Thanks that really works. But it requires to use top level await for using shared on the side of the host.
To use top level await you can either set build target to esnext or to use external plugin for vite like https://github.com/Menci/vite-plugin-top-level-await
But both options breaks for me cypress tests in the Gitlab pipelines. And esnext target drops support for older browsers, which is not nice

@raffidahmad
Copy link

@raffidahmad Thanks that really works. But it requires to use top level await for using shared on the side of the host.
To use top level await you can either set build target to esnext or to use external plugin for vite like https://github.com/Menci/vite-plugin-top-level-await
But both options breaks for me cypress tests in the Gitlab pipelines. And esnext target drops support for older browsers, which is not nice

Ah you must be using static imports then correct?
If you use dynamic imports you shouldn't need to use the top level await

@kirill-dev-pro
Copy link

@raffidahmad Thanks that really works. But it requires to use top level await for using shared on the side of the host.
To use top level await you can either set build target to esnext or to use external plugin for vite like https://github.com/Menci/vite-plugin-top-level-await
But both options breaks for me cypress tests in the Gitlab pipelines. And esnext target drops support for older browsers, which is not nice

Ah you must be using static imports then correct? If you use dynamic imports you shouldn't need to use the top level await

@raffidahmad not sure, actually
I use remote imports as

const RemoteComponent = lazy(() => import('remote/Component'));

Looks like dynamic import call. What is another option?

@kirill-dev-pro
Copy link

kirill-dev-pro commented Feb 7, 2024

Tryed to use remote component with static imports, like so

import RemoteLocal from 'remote/Component';

and almost the same error with vite build

[vite:esbuild-transpile] Transform failed with 1 error:
assets/index-!~{001}~.js:406159:52: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)

Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
406157|  };
406158|  
406159|  const __federation_var_stageandgatelocalComponent = await __federation_method_getRemote("remote" , "./Component");
   |                                                      ^
406160|   let RemoteLocal = __federation_method_unwrapDefault(__federation_var_stageandgatelocalComponent); 
406161|  const Projects = () => {

✓ built in 16.60s

@CerealPlayer
Copy link
Author

have you tried setting 'react' & reactdom in the shared property?

I did, it's in the repo, and the federation plugin downloads both react versions but they get mixed somehow, so one copy is aware of the other and that in react results in errors (only 1 react copy allowed).

Ideally, both react versions are donwloaded, and the code from remote only imports from remote's react version and the code from host only imports from host's react version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants