vite-plugin-federation
vite-plugin-federation copied to clipboard
React Microfrontend does not work on an app with different React versions
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.
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.
have you tried setting 'react' & reactdom in the shared property?
@raffidahmad but what if you dont want to share react version?
@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
@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 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 toesnext
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 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 toesnext
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 niceAh 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?
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
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