vite-plugin-federation
vite-plugin-federation copied to clipboard
Importing federated module name via variable
Versions
- vite-plugin-federation: v1.2.2
- vite: v4.2.0
Reproduction
I trying to lazy load a federated module in my React application. It works if the import link is a string, it doesn't work if the import link is stored in a variable.
Example:
This works:
const MyModule = React.lazy(() => import("FederatedAppName/ComponentName");
This does not work:
const appName = "FederatedAppName/ComponentName"; const MyModule = React.lazy(() => import(appName);
Why do I want to do this? I get the information about the modules that should be used as federated module from an API. In the API result I get the component name and the app name and all information that is required to dynamically load the required apps. To simulate this I have created a json file where I put the same information. You can find my example application here: https://github.com/iconag-bbasmer/vite-module-federation-test.git
Check the conainer/scr/main.tsx to see how I try to lazy load the federated components. You can see in line 12 and 13 of the file how things work and how they don't.
I have also encountered the same problem as you, and after researching for several days, I only found two methods. I am not sure if they are correct.
Remote Vite configuration:
federation({
name: './remote-component',
filename: 'remoteEntry.js',
// Modules to expose
exposes: {
'./remote-text.js': './src/components/text/material.vue',
'./remote-image.js': './src/components/image/material.vue',
},
shared: ['vue']
})
references #157
Method 1:
const remotesMap: any = {};
remotesMap[ './remote-component'] = {
url: "http://localhost:4174/assets/remoteEntry.js",
format: 'esm',
from: 'vite'
}
const url = './remote-image.js'
const comp = await __federation_method_getRemote('./remote-component', url);
return comp.default
Method 2:
const url = './remote-image.js'
const remote = await import('http://localhost:4174/assets/remoteEntry.js');
const comp = await remote.get(url)
return comp().default
I have implemented a mix of both now and it works as long as I don't use any React Hooks in the remotes. As soon as I add a Hook (useEffect or useState for example) the remote breaks. I have updated the repo mentioned above. In vapp1/src/components/AppHeader.tsx I have commented out some test code using Hooks. I this gets activated, the apps get built and run, loading the Vapp1 breaks and it gives this error:
TypeError: U.current is null
Maybe I need to do something different when loading the remotes (see container/src/components/RemoteComponent/index.tsx)?
Btw, when trying Method 1, it tells me that __federation_method_getRomote can't be found and I'm not sure how I could add this.
/Method 1 equires at least one static import of a remote module. You can pre-loading a remote module, which can be empty, but cannot be a variable import, and "must" be used, otherwise function '__federation_method_getRemote' will not be included during packaging.
For example, a remote website can expose an empty object:
empty.ts
export default {}
vite.config.js
federation({
name: './remote-component',
filename: 'remoteEntry.js',
// Modules to expose
exposes: {
'./remote.js': './src/components/index.ts',
'./empty': './src/components/empty.ts'
},
shared: ['vue']
})
Then in the host code:
vite.config.js
federation({
name: 'host-app',
remotes: {
'./remote-component': {
external:`new Promise(resolve=>resolve('http://localhost:4174/assets/remoteEntry.js'))`,
externalType:"promise"
},
},
shared: ['vue']
}),
load.js
// here, preload an empty file
import empty from './remote-component/empty'
// must be used
// otherwise function '__federation_method_getRemote' will not be included during packaging.
const EMPTY = empty
async function loadCompConfig(remoteUrl: string) {
// @ts-ignore
const remoteEntry = await __federation_method_getRemote("./remote-component", remoteUrl);
// ... other code
}
This code is a bit hacky, but it works.
For Method 2, there are too many uncertainties.
Ok, I updated my test application and got one step further. :-) Now the thing is that I can't add the components that I want to load into the global remotesMap object, used by the federation plugin. I have added my remotes to my local remotesMap object but that doesn't work and I get the error message:
TypeError: remote is undefined
in __federation_method_ensure
I debugged it and indeed, the modules I want to load are not in there, only the ones that should be loaded statically. Also, whenever I add a remotesMap object to my code, the federation plugin renames its own remotesMap object to remotesMap$1 so I can't access it anymore to add my components to it.
In my example repo I have updated /container/src/components/RemoteComponent/index.tsx and added the changes from your post(s) above.
If you have an idea how to add to the remotesMap object created by the federation plugin, please let me know.
Thanks a lot!
Ok. Another step taken and still no step forward.
I forked the module federation plugin and added a __federation_method_setRemote
function that I found in the discussions of the module federation plugin git repo. After trying a lot of things it works at least sometimes. :-) The issue is that it is not stable. If you refresh the browser and hit the "Load Modules" button and do both multiple times you get different results. Sometimes it loads the App1 and sometimes this one fails and the error message is U.current is null
which is the same error message as described above. It comes up because I use React state in this module and it seems that React is not available at the point when the module is loading, at least that's what I suspect. Unfortunately I have no answer to this and I guess I will have to drop using Vite because I need the module federation plugin to be stable and with webpack this just works perfectly out of the box.
I have updated my example repo.
There is a discussion about this, with the setRemote methode but no confirmation yet. https://github.com/originjs/vite-plugin-federation/discussions/193#discussioncomment-5241087
I have the same problem, dynamic imports not run
@iconag-bbasmer Have you been able to achieve your first goal?
const appName = "FederatedAppName/ComponentName"; const MyModule = React.lazy(() => import(appName);
I have not and I have stopped trying already a while ago. I dropped working with Vite as a whole and work now with Nx with Webpack to generate my remotes which works perfectly. Nx is a whole different story, I know but for me it actually is the perfect solution for working with my projects. And I think nowadays they even have an integration with Vite also. But I haven't tried it yet together with the module federation.
I have not and I have stopped trying already a while ago. I dropped working with Vite as a whole and work now with Nx with Webpack to generate my remotes which works perfectly. Nx is a whole different story, I know but for me it actually is the perfect solution for working with my projects. And I think nowadays they even have an integration with Vite also. But I haven't tried it yet together with the module federation.
Thanks for your answer.
I have not and I have stopped trying already a while ago. I dropped working with Vite as a whole and work now with Nx with Webpack to generate my remotes which works perfectly. Nx is a whole different story, I know but for me it actually is the perfect solution for working with my projects. And I think nowadays they even have an integration with Vite also. But I haven't tried it yet together with the module federation.
This is what I'm trying to achieve https://github.com/originjs/vite-plugin-federation/issues/518, in your experience do you think that Nx and Webpack could be a solution for me?
Well, that depends heavily on your needs. Nx itself is a beast to understand and work with but once I understood the concepts, I really like it. They have generators for the remotes that you use with your Module Federation and so on. It's very handy and can do a lot of things. But it's also quite complicated to handle. I'd suggest to check it out with a POC to see how it works. The also have generators for Vite but I don't think that the MF is already integrated too as it is with Webpack.
Well, that depends heavily on your needs. Nx itself is a beast to understand and work with but once I understood the concepts, I really like it. They have generators for the remotes that you use with your Module Federation and so on. It's very handy and can do a lot of things. But it's also quite complicated to handle. I'd suggest to check it out with a POC to see how it works. The also have generators for Vite but I don't think that the MF is already integrated too as it is with Webpack.
Thanks, I think indeed its quiet heavy for my needs.
For reference: https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations