How to properly setup ModuleFederation and react-router-dom
so that I can have
Router
and routes defined inHost
app- and remote
Header
app has<Link>
ponents pointing to the routes defined in Host?
However, the setup below fails to the following error:
index.js:15 Uncaught Error: useHref() may be used only in the context of a <Router> ponent.
The setup:
Host mfe app, 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>)
}
...
Host's 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 app, 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's 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"],
}
},
}),
...
But, if I wrap also Header
in BrowserRouter
I encounter the following error instead:
index.js:15 Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
How to properly setup ModuleFederation and react-router-dom
so that I can have
Router
and routes defined inHost
app- and remote
Header
app has<Link>
ponents pointing to the routes defined in Host?
However, the setup below fails to the following error:
index.js:15 Uncaught Error: useHref() may be used only in the context of a <Router> ponent.
The setup:
Host mfe app, 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>)
}
...
Host's 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 app, 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's 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"],
}
},
}),
...
But, if I wrap also Header
in BrowserRouter
I encounter the following error instead:
index.js:15 Uncaught Error: You cannot render a <Router> inside another <Router>. You should never have more than one in your app.
- Was your issue solved? – Arjun Mudhaliyar Commented Nov 15, 2022 at 13:42
1 Answer
Reset to default 3In your remote app you should wrap your header ponent inside a BrowserRouter, but the ponent that contains the BrowserRouter should not be exposed. In the example I am using react-router-dom v6.
Use another ponent (in my example it's Test.js, which will be used inside index.js, but this won't be exposed by the module federation and it is used just for local development of the remote app). Header is the ponent that you want to expose to module federation and use in the other app (as you have it already in your webpack config)
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;
Then in your host app you can use the Header ponent in a similar way as you would in the remote app.
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;
The idea is the remote app needs the header to run inside a BrowserRouter for local development, but when used in a host application the Header ponent will use the BrowserRouter from the host application, since the BrowserRouter from the remote app is not exposed anywhere by the module federation.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744263000a4565727.html
评论列表(0条)