Replies: 21 comments 29 replies
-
I looked at const remotesMap = {
'home': {url: 'http://localhost:5001/assets/remoteEntry.js', format: 'esm'},
'common-lib': {url: 'http://localhost:5002/assets/remoteEntry.js', format: 'esm'},
'css-modules': {url: 'http://localhost:5003/assets/remoteEntry.js', format: 'esm'}
};
const loadJS = (url, fn) => {
const script = document.createElement('script');
script.type = 'text/javascript';
script.onload = fn;
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
};
const scriptTypes = ['var'];
const importTypes = ['esm', 'systemjs'];
const metaGet = name => __federation_import(name);
const webpackGet = name => metaGet(name).then(module => () => module?.default ?? module);
const shareScope = {
'vue': {
'3.2.23': {
metaGet: () => metaGet('./__federation_shared_vue.js'),
get: () => webpackGet('./__federation_shared_vue.js'),
loaded: 1
}
},
'vuex': {
'4.0.2': {
metaGet: () => metaGet('./__federation_shared_vuex.js'),
get: () => webpackGet('./__federation_shared_vuex.js'),
loaded: 1
}
}
};
async function __federation_import(name) {
return __vitePreload(() => import(name), true ? [] : void 0);
}
var __federation__ = {
ensure: async (remoteId) => {
const remote = remotesMap[remoteId];
if (!remote.inited) {
if (scriptTypes.includes(remote.format)) {
// loading js with script tag
return new Promise(resolve => {
const callback = () => {
if (!remote.inited) {
remote.lib = window[remoteId];
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
};
loadJS(remote.url, callback);
});
} else if (importTypes.includes(remote.format)) {
// loading js with import(...)
return new Promise(resolve => {
__vitePreload(() => import(/* @vite-ignore */ remote.url), true ? [] : void 0).then(lib => {
if (!remote.inited) {
lib.init(shareScope);
remote.lib = lib;
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
});
})
}
} else {
return remote.lib;
}
}
}; This code shows how to initialize a remote component, note that the logic of loading a remote component generated by webpack is different from that of loading a remote component generated by vite-plugin-federation, because webpack uses iife by default and needs to be loaded using <script src=... > to load them, while for vite-plugin-federation they will be loaded directly using esm's import |
Beta Was this translation helpful? Give feedback.
-
Brilliant! Thank you for the quick reply, I'll have a play around w/ the code.
Yes indeed, the webpack example just switches things in and out. It looks it could be adapted into something more generic that could hopefully take a list of remotes from some other source and display them all in a navbar / menu for example. |
Beta Was this translation helpful? Give feedback.
-
Code works great for prod! const RemoteButton = React.lazy(
// Normal way of loading things
// @ts-ignore
// import("remote_app/Button")
// Use new loader
() => {
remotesMap["remote_app"] = {
url: "http://localhost:5001/assets/remoteEntry.js",
format: "esm",
};
return __federation__
.ensure("remote_app")
.then((remote) => remote.get("./Button").then((factory) => factory()));
}
); Dev looks a bit more hairy.. 🤔 . Could we expose the This is a bit hacky. I guess it would be neat to have some runtime lib |
Beta Was this translation helpful? Give feedback.
-
Sorry, I guess the "problem" now is how to get
Perhaps we could always set |
Beta Was this translation helpful? Give feedback.
-
I have something to say about dev mode, because vite does not support adding a bundle in dev mode (actually it is the remoteEntry.js file), so now the dev mode of vite-plugin-federation only supports the host side, the remote side cannot run in dev mode.
|
Beta Was this translation helpful? Give feedback.
-
It sounds crazy to load the shared before loading the module,Perhaps we need to seriously consider how to achieve this, because in theory we need to determine which shared libraries are used by the component and then load the corresponding shared, it's the Chinese New Year, my reply may be late, don't mind
|
Beta Was this translation helpful? Give feedback.
-
I dont realy know how to get the missing variables remotesMap and federation |
Beta Was this translation helpful? Give feedback.
-
@T0miii I think the current does not fully provide open |
Beta Was this translation helpful? Give feedback.
-
Hi everyone! |
Beta Was this translation helpful? Give feedback.
-
@foot Hi, i dont know if you are still working with federation, but did you manage to make dynamic imports work? when i try doing the following vite still errors out, saying it cant resolve app/Counter. |
Beta Was this translation helpful? Give feedback.
-
+1, think it will be a killer feature :D |
Beta Was this translation helpful? Give feedback.
-
🎉
|
Beta Was this translation helpful? Give feedback.
-
I arrived a bit later to this, but really interested in this feature, it will sadly be a blocker for us and become a turning point to switch out of vite if we can't do this dynamic module federation imports for our new product. Any status updates from people on the thread? |
Beta Was this translation helpful? Give feedback.
-
The issue is solved with latest release. Thanks to everyone involved. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
This might be and hopefully someone has some insight, but here's my issue as of now as soon as using hooks.
Both the host and remote uses the the same react and react-dom version, although I likely think the shared thingy is the issue. This is how I'm loading the app (works just fine without hooks) __federation_method_setRemote(scope, {
url: () => Promise.resolve(url),
format: 'esm',
from: 'vite',
});
const mWrapper = await __federation_method_getRemote(scope, './config');
const m = await __federation_method_unwrapDefault(mWrapper);
const appConfig = m();
console.log('Loaded external app config', appConfig);
const config = appConfig;
config.Component = (props: object) => React.createElement(config.app, props);
const Provider = createExternalAppProvider(config);
config.Route = (props: any) => {
return (
<Route path={config.path}>
<Provider>
<config.Component />
</Provider>
</Route>
); I've got the remote vite config: export default defineConfig({
plugins: [
react(),
federation({
name: 'mockapp',
filename: 'remoteEntry.js',
exposes: {
'./config': './npwd.config.ts',
},
shared: ["react", 'react-dom']
}),
topLevelAwait({
// The export name of top-level await promise for each chunk module
promiseExportName: "__tla",
// The function to generate import names of top-level await promise in each chunk module
promiseImportName: i => `__tla_${i}`
})
],
server: {
port: 3002,
},
build: {
modulePreload: false,
}
}); Here's the npwd.config.ts file: import App from './src/App';
import { AppIcon } from './icon';
interface Settings {
language: 'en';
}
export const path = '/mockapp';
export default (settings: Settings) => ({
id: 'MOCKAPP',
path,
nameLocale: "Mockapp",
color: '#fff',
backgroundColor: '#333',
icon: AppIcon,
app: App,
}); and then a very simple App component: import React, { useState } from 'react';
import { i18n } from 'i18next';
interface AppProps {
theme: any;
i18n: i18n;
settings: any;
}
export function Counter() {
const [counter, setCounter] = useState(0);
return (
<div style={{ color: "white" }}>
<h1>HELLLO WORLD</h1>
<p>Counter: {counter}</p>
<button onClick={() => setCounter((prev) => prev + 1)}>Increment</button>
</div>
);
}
export function App() {
return (
<div style={{ color: "white" }}>
<h1>HELLLO WORLD</h1>
<Counter />
</div>
);
};
export default function WithProviders() {
return (
<App />
)
} |
Beta Was this translation helpful? Give feedback.
-
any update on this? |
Beta Was this translation helpful? Give feedback.
-
Anyone get it to work with Host in dev mode, and Remotes in production mode? Based in the READMD.md it should work, but read me only have the example static hosting I'm getting this error when Host in dev mode, and Remotes in production mode, when loading the Remotes |
Beta Was this translation helpful? Give feedback.
-
So I've managed to make the dynamic import work: const RemoteApp = lazy(() => {
__federation_method_setRemote(`remote-${id}`, {
url: () => Promise.resolve(remote),
format: 'esm',
from: 'vite',
});
return __federation_method_getRemote(`remote-${id}`, component);
}); The main issue is when writting tests for the components then the federation module is not available. Has anyone manage to write tests and simulate the module: federation
|
Beta Was this translation helpful? Give feedback.
-
Just started working on Vite with micro front, from all the above discussions I could able to load the remote component only in prod not in dev mode. And when I stop the remote the host/shell goes blank. This would be easily achievable with Webpack . Just let me is this a vite's limitation. |
Beta Was this translation helpful? Give feedback.
-
Does anyone know if it's possible to use shared libraries with dynamic federation? I suppose the host config should include a |
Beta Was this translation helpful? Give feedback.
-
Is your feature request related to a problem? Please describe.
We want to get a list of remotes at runtime from another api service. e.g.
GET /api/services
. From the examples here I can only see how to do this at build time by specifying the remotes invite.config.js
or rollup config.Describe the solution you'd like
We would like to dynamically load remotes at runtime, here is an example of doing it w/ webpack and their "container" model:
https://github.com/module-federation/module-federation-examples/blob/master/dynamic-system-host/app1/src/App.js
I've had a bit of look into some of the code in expose-dev.ts but its still early for me.
Does this sound feasible?
Describe alternatives you've considered
Trying to use systemjs perhaps?
Beta Was this translation helpful? Give feedback.
All reactions