简体   繁体   English

Webpack 模块联合和 react-router-dom

[英]Webpack module federation and react-router-dom

How to properly setup ModuleFederation and react-router-dom so that I can have如何正确设置 ModuleFederation 和react-router-dom以便我可以拥有

  • Router and routes defined in Host app Host应用程序中定义的Router和路由
  • and remote Header app has <Link> components pointing to the routes defined in Host?和远程Header应用程序有<Link>组件指向主机中定义的路由?

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> component.

The setup:设置:

Host mfe app, localhost:3001主机 mfe 应用程序,本地主机: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主机的 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 Header mfe 应用程序,本地主机: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标头的 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:但是,如果我在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.

In your remote app you should wrap your header component inside a BrowserRouter, but the component that contains the BrowserRouter should not be exposed.在您的远程应用程序中,您应该将 header 组件包装在 BrowserRouter 中,但不应公开包含 BrowserRouter 的组件。 In the example I am using react-router-dom v6.在示例中,我使用的是 react-router-dom v6。

Use another component (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).使用另一个组件(在我的示例中是 Test.js,它将在 index.js 中使用,但这不会被模块联合公开,它仅用于远程应用程序的本地开发)。 Header is the component that you want to expose to module federation and use in the other app (as you have it already in your webpack config) 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;

Then in your host app you can use the Header component in a similar way as you would in the remote app.然后在您的主机应用程序中,您可以像在远程应用程序中一样使用 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;

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 component will use the BrowserRouter from the host application, since the BrowserRouter from the remote app is not exposed anywhere by the module federation.这个想法是远程应用程序需要 header 在 BrowserRouter 内运行以进行本地开发,但是当在主机应用程序中使用时,Header 组件将使用来自主机应用程序的 BrowserRouter,因为来自远程应用程序的 BrowserRouter 不会在任何地方被模块联合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM