Webpack 模块联合和 react-router-dom
Webpack module federation and react-router-dom
如何正确设置 ModuleFederation 和 react-router-dom
以便我可以
Router
和 Host
app 中定义的路由
- 并且远程
Header
应用程序有 <Link>
组件指向 Host? 中定义的路由
但是,下面的设置失败并出现以下错误:
index.js:15 Uncaught Error: useHref() may be used only in the context of a <Router> component.
设置:
托管 mfe 应用,localhost:3001
...
import { BrowserRouter } from 'react-router-dom'
const Header = lazy(() => import("header/Header"))
const Host = () => {
return (
<BrowserRouter>
<React.Suspense fallback="Loading Header...">
<Header />
</React.Suspense>
<Switch>
<Route path="/input">
<InputFormView />
</Route>
<Route path="/">
<ListView />
</Route>
</Switch>
</BrowserRouter>)
}
...
主持人的webpack.config.js
...
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
header: 'header@http://localhost:3002/remoteEntry.js'
},
exposes: {
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"react-router-dom": {
singleton: true,
requiredVersion: deps["react-router-dom"],
}
},
}),
...
Header mfe 应用程序,localhost:3002
...
import { Link } from 'react-router-dom'
const Header = () => {
return (
<div id="header">
<h1> Header </h1>
<Link to="/input">
<button type="button"> Input form </button>
</Link>
</div>
)
...
Header的webpack.config.js
...
new ModuleFederationPlugin({
name: 'header',
filename: 'remoteEntry.js',
exposes: {
'./Header': './src/Components/Header'
},
remotes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"react-router-dom": {
singleton: true,
requiredVersion: deps["react-router-dom"],
}
},
}),
...
但是,如果我也将 Header
包装在 BrowserRouter
中,则会遇到以下错误:
index.js:15 Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
在您的远程应用程序中,您应该将 header 组件包装在 BrowserRouter 中,但不应公开包含 BrowserRouter 的组件。在示例中,我使用 react-router-dom v6.
使用另一个组件(在我的示例中它是 Test.js,它将在 index.js 内部使用,但这不会被模块联合公开,它仅用于本地开发远程应用程序)。 Header 是您要向模块联合公开并在其他应用程序中使用的组件(因为您已经在您的 webpack 配置中拥有它)
import React from 'react';
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import Header from './Header';
const localRouter = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<div>home<Header></Header></div>}></Route>
<Route path="input"element={<div>input</div>}/>
</Routes>
</BrowserRouter>)
}
export default localRouter;
然后在您的主机应用程序中,您可以像在远程应用程序中一样使用 Header 组件。
import React from 'react';
import {
BrowserRouter,
Routes,
Route,
Link
} from "react-router-dom";
const Header = React.lazy(() => import('header/Header'));
const HostApp = () => (
<>
<div>Hello, I'm the host app!</div>
<BrowserRouter>
<Routes>
<Route path="/" element={<div>home
<React.Suspense fallback="loading...">
<Header />
</React.Suspense>
</div>}></Route>
<Route path="input"element={<div>input</div>}/>
... some other routes
</Routes>
</BrowserRouter>
</>
);
export default HostApp;
想法是远程应用程序需要 BrowserRouter 中的 header 到 运行 用于本地开发,但是当在主机应用程序中使用时,Header 组件将使用 BrowserRouter 来自主机应用程序,因为来自远程应用程序的 BrowserRouter 不会被模块联合暴露在任何地方。
如何正确设置 ModuleFederation 和 react-router-dom
以便我可以
Router
和Host
app 中定义的路由
- 并且远程
Header
应用程序有<Link>
组件指向 Host? 中定义的路由
但是,下面的设置失败并出现以下错误:
index.js:15 Uncaught Error: useHref() may be used only in the context of a <Router> component.
设置:
托管 mfe 应用,localhost:3001
...
import { BrowserRouter } from 'react-router-dom'
const Header = lazy(() => import("header/Header"))
const Host = () => {
return (
<BrowserRouter>
<React.Suspense fallback="Loading Header...">
<Header />
</React.Suspense>
<Switch>
<Route path="/input">
<InputFormView />
</Route>
<Route path="/">
<ListView />
</Route>
</Switch>
</BrowserRouter>)
}
...
主持人的webpack.config.js
...
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
header: 'header@http://localhost:3002/remoteEntry.js'
},
exposes: {
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"react-router-dom": {
singleton: true,
requiredVersion: deps["react-router-dom"],
}
},
}),
...
Header mfe 应用程序,localhost:3002
...
import { Link } from 'react-router-dom'
const Header = () => {
return (
<div id="header">
<h1> Header </h1>
<Link to="/input">
<button type="button"> Input form </button>
</Link>
</div>
)
...
Header的webpack.config.js
...
new ModuleFederationPlugin({
name: 'header',
filename: 'remoteEntry.js',
exposes: {
'./Header': './src/Components/Header'
},
remotes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"react-router-dom": {
singleton: true,
requiredVersion: deps["react-router-dom"],
}
},
}),
...
但是,如果我也将 Header
包装在 BrowserRouter
中,则会遇到以下错误:
index.js:15 Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
在您的远程应用程序中,您应该将 header 组件包装在 BrowserRouter 中,但不应公开包含 BrowserRouter 的组件。在示例中,我使用 react-router-dom v6.
使用另一个组件(在我的示例中它是 Test.js,它将在 index.js 内部使用,但这不会被模块联合公开,它仅用于本地开发远程应用程序)。 Header 是您要向模块联合公开并在其他应用程序中使用的组件(因为您已经在您的 webpack 配置中拥有它)
import React from 'react';
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import Header from './Header';
const localRouter = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<div>home<Header></Header></div>}></Route>
<Route path="input"element={<div>input</div>}/>
</Routes>
</BrowserRouter>)
}
export default localRouter;
然后在您的主机应用程序中,您可以像在远程应用程序中一样使用 Header 组件。
import React from 'react';
import {
BrowserRouter,
Routes,
Route,
Link
} from "react-router-dom";
const Header = React.lazy(() => import('header/Header'));
const HostApp = () => (
<>
<div>Hello, I'm the host app!</div>
<BrowserRouter>
<Routes>
<Route path="/" element={<div>home
<React.Suspense fallback="loading...">
<Header />
</React.Suspense>
</div>}></Route>
<Route path="input"element={<div>input</div>}/>
... some other routes
</Routes>
</BrowserRouter>
</>
);
export default HostApp;
想法是远程应用程序需要 BrowserRouter 中的 header 到 运行 用于本地开发,但是当在主机应用程序中使用时,Header 组件将使用 BrowserRouter 来自主机应用程序,因为来自远程应用程序的 BrowserRouter 不会被模块联合暴露在任何地方。