我有一个使用react和vite的项目,我使用@module-federation/vite设置了一个微前端方法来获取遥控器,也在遥控器中使用相同的堆栈和配置。现在我想要从模块联合动态遥控器以便能够在运行时加载遥控器。根据模块联合文档,使用此插件是不可能的,但可以使用Federation Runtime来完成。对于主机应用程序来说,这是加载遥控器
import React, { useState, useEffect, Suspense, lazy } from "react";
import { init, loadRemote, registerRemotes } from "@module-federation/enhanced/runtime";
import ErrorBoundary from "../errorBoundary";
init({
name: "remote",
remotes: [
{
name: "remote",
entry: "http://localhost:4174/remoteEntry.js",
},
],
});
const useRemote = (scope: string, module: string) => {
const LazyComponent = lazy(async () => {
// registerRemotes([
// {
// name: "remote",
// entry: "http://localhost:4174/remoteEntry.js",
// },
// {
// name: "remoteToolbox",
// entry: "http://localhost:4175/remoteEntry.js",
// },
// ]);
return loadRemote<{ default: any }>(`${scope}/${module}`, {
from: "runtime",
}) as Promise<{ default: any }>;
});
return (props: any) => {
const [{ module, scope }, setSystem] = useState<any>({});
const setApp2 = () => {
setSystem({
scope: "remote",
module: "remote-menu",
});
};
const setApp3 = () => {
setSystem({
scope: "remoteToolbox",
module: "remote-toolbox",
});
};
return (
<div
style={{
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
}}
>
<h1>Dynamic System Host</h1>
<h2>App 1</h2>
<p>
The Dynamic System will take advantage of Module Federation{" "}
<strong>remotes</strong> and <strong>exposes</strong>. It will not
load components that have already been loaded.
</p>
<button onClick={setApp2}>Load App 2 Widget</button>
<button onClick={setApp3}>Load App 3 Widget</button>
<div style={{ marginTop: "2em" }}>
<ErrorBoundary>
<LazyComponent {...props} />
</ErrorBoundary>
</div>
</div>
);
};
};
export default useRemote;
使用远程组件:
function Home() {
const App = useRemote("remote", "remote-menu");
return (
<ErrorBoundary>
<Suspense>
<App />
</Suspense>
</ErrorBoundary>
);
}
主机组件的 vite 配置设置为虚拟远程:
import { fileURLToPath, URL } from "node:url";
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import { federation } from '@module-federation/vite';
// https://vitejs.dev/config/
export default defineConfig(({ mode }: any) => {
const selfEnv = loadEnv(mode, process.cwd());
const remoteSideMenuUrl = selfEnv.VITE_REMOTE_SIDE_MENU_URL;
const remoteToolboxUrl = selfEnv.VITE_REMOTE_TOOLBOX_URL;
return {
server: {
fs: {
allow: ['.'],
},
},
build: {
target: 'esnext', minify: false, cssCodeSplit: false,
commonjsOptions: {
include: ["tailwind.config.js", "node_modules/**"],
},
},
optimizeDeps: {
include: ["tailwind-config"],
},
plugins: [
federation({
name: 'ShellApp',
remotes: {
dummy: "dummy.js",
// remote: {
// type: 'module',
// name: 'remote',
// entry: remoteSideMenuUrl + '/remoteEntry.js',
// entryGlobalName: 'remote',
// shareScope: 'default',
// },
// remoteToolbox: {
// type: 'module',
// name: 'remoteToolbox',
// entry: remoteToolboxUrl + '/remoteEntry.js',
// entryGlobalName: 'remoteToolbox',
// shareScope: 'default',
// },
},
exposes: {},
filename: 'remoteEntry.js',
//shared: ['react', 'react-dom', 'react-router-dom', "tailwindcss"],
}),
react(),
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
"tailwind-config": fileURLToPath(
new URL("./tailwind.config.js", import.meta.url)
),
},
},
}
});
这是 vite.conf.ts
import { federation } from '@module-federation/vite';
import react from '@vitejs/plugin-react';
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const selfEnv = loadEnv(mode, process.cwd());
return {
base: "./",
server: {
fs: {
allow: ['.'],
},
},
build: {
target: 'esnext',
},
plugins: [
federation({
filename: 'remoteEntry.js',
name: 'remote',
exposes: {
'./remote-menu': './src/App.tsx',
},
remotes: {},
shared: ['react', 'react-dom', 'react-router-dom'],
}),
react(),
],
};
});
构建在主机中运行良好,但是当我在浏览器中打开应用程序时,出现此错误:
index-DcUMJ190.js:375 Error: [ Federation Runtime ]: Failed to get remoteEntry exports.
args: {"remoteName":"remote","remoteEntryUrl":"http://localhost:4174/remoteEntry.js","remoteEntryKey":"remote"}
https://module-federation.io/guide/troubleshooting/runtime/RUNTIME-001
at error (ShellApp__mf_v__runtimeInit__mf_v__-B_MJuhnz.js:1086:11)
at Object.assert (ShellApp__mf_v__runtimeInit__mf_v__-B_MJuhnz.js:1078:9)
at ShellApp__mf_v__runtimeInit__mf_v__-B_MJuhnz.js:2184:16
我尝试按照此示例存储库更改遥控器和主机中的配置:https://github.com/RussellCanfield/nx-rspack-microfrontend-demo/blob/dynamic-loader/apps/mfe-monorepo/src/app/功能/主页/组件/Home.tsx
但不同的是,我这边有vite。
你们中的一些人尝试过这种动态远程方法吗?
对于可能需要它的人,这解决了我的问题:
init({
name: "ShellApp",
remotes: [
{
type: "module",
name: "remote",
entry: "http://localhost:4174/remoteEntry.js",
},
{
type: "module",
name: "remoteToolbox",
entry: "http://localhost:4175/remoteEntry.js",
},
],
});