首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >微前端无效钩子调用

微前端无效钩子调用
EN

Stack Overflow用户
提问于 2022-07-17 19:06:16
回答 1查看 234关注 0票数 0

我有一个具有以下结构的微前端应用程序。我试图同时安装市场营销和公司集装箱,但不断得到无效的钩子呼叫。它们都使用react 18.2、react dom 18.2和react路由器-dom 6.3.0.营销本身在浏览器中加载很好,但是当试图将其加载到容器时,我会得到一个无效的钩子调用警告。怎么一回事?我可以在容器(主机)中使用Router,在市场(远程)中使用BrowserRouter吗?

代码语言:javascript
复制
/packages
|  /company
|  |  /public
|  |  /src
|  /marketing
|  |  /public
|  |  /src
|  /container
|  |  /public
|  |  /src

容器: App.js

代码语言:javascript
复制
import React, { lazy, Suspense, useState, useEffect } from 'react';
import { Router, Route, Routes, Navigate } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    height: 100%;
    min-height: 100vh;
  }

  html {
    height: 100%;
  }
`

import WebFont from 'webfontloader';

WebFont.load({
  google: {
    families: ['Barlow', 'Playfair Display', 'Overpass']
  }
});

// deleted because we are now using lazy function and Suspense module
// import MarketingApp from './components/MarketingApp';
// import AuthApp from './components/AuthApp';
import Progress from './components/Navbar/Progress';
import Header from './components/Header';

const MarketingLazy = lazy(() => import('./components/MarketingApp'));
const CompaniesLazy = lazy(() => import('./components/CompanyApp'));

const history = createBrowserHistory();

export default function App() {
  // useState is a HOOK to keep track of the application state IN A FUNCTION COMPONENT, in this case if the user isSignedIn
  // State generally refers to data or properties that need to be tracking in an application
  // hooks can only be called at the top level of a component; cannot be conditional; and can only be called inside React function commponents 
  // useState accepts an initial state and returns two values: the current state, and a function that updates the state 
  const [isSignedIn, setIsSignedIn] = useState(false);

  // 
  useEffect(() => {
    if (isSignedIn) {
      history.push('/companies/last')
    }
  }, [isSignedIn]);


  return (
    <Router history={history}>
      <div>
        <GlobalStyle />
        <Header onSignOut={() => setIsSignedIn(false)} isSignedIn={isSignedIn} />
        <Suspense fallback={<Progress />} >
          <Routes>
            ...
            <Route path="/" element={ <MarketingLazy /> } />
          </Routes>
        </Suspense>
      </div>
    </Router>
  );
};

容器: MarketingApp.js从市场部导入mount函数(远程)

代码语言:javascript
复制
import { mount } from 'marketingMfe/MarketingApp';
import React, { useRef, useEffect, useContext } from 'react';
import { useLocation, UNSAFE_NavigationContext } from 'react-router-dom';

export default () => {
  const ref = useRef(null);
  let location = useLocation();
  const { navigator } = useContext(UNSAFE_NavigationContext);
  
  useEffect(() => {
    const { onParentNavigate } = mount(ref.current, {
      initialPath: location.pathname,
      onNavigate: ({ pathname: nextPathname }) => {        
        const { pathname } = navigator.location;

        if (pathname !== nextPathname) {
          navigator.push(nextPathname);
        }
      },
    });

    const unlisten = navigator.listen(onParentNavigate);

    return unlisten; // <-- cleanup listener on component unmount

  }, []);

  return <div ref={ref} />;
};

营销: App.js

代码语言:javascript
复制
import React from 'react';
import { Routes, Route, BrowserRouter as Router } from 'react-router-dom';

import Landing from './components/Landing';
import EarlyAccess from './components/LandingPages/EarlyAccess';

import WebFont from 'webfontloader';

if (process.env.NODE_ENV === 'development') {
  WebFont.load({
    google: {
      families: ['Barlow', 'Playfair Display', 'Overpass']
    }
  });
}

export default ({ history }) => {

  return (
    <div>
      <Router location={history.location} history={history}>
        <Routes>
          <Route exact path="/earlyaccess" element={ <EarlyAccess /> } />
          <Route exact path="/learn" element={ <EarlyAccess /> } />
          <Route path="/" element={ <Landing /> } />
        </Routes>
      </Router>
    </div>
  );
};

营销: bootstrap.js在运行容器(主机)时导出mount功能

代码语言:javascript
复制
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createMemoryHistory, createBrowserHistory } from 'history';

import App from './App';

// Mount function to start up the app
// NOTE: if you update mount parameters then change the code for running the app in isolation below this definition
const mount = (el, { onNavigate, defaultHistory }) => {
  // if given a default history object, assign it to history; otherwise use MemoryHistory object
  const history = defaultHistory || createMemoryHistory();

  if (onNavigate) {
    history.listen(onNavigate); // event listener tied to the history object which listens to whenever navigation occur
  }

  const root = ReactDOM.createRoot(el);

  root.render(
    <React.StrictMode>
      <App history={history} />
    </React.StrictMode>
  );

  return{
    onParentNavigate({ pathname: nextPathname }) {
      console.log('Container-marketing just navigated.');
      // console.log(location);

      const { pathname } = history.location;

      // avoid getting into an infinite loop
      if (pathname !== nextPathname) {
        history.push(nextPathname);
      }
    },
  };
};

// If we are in development and in isolation,
// call mount immediately
if (process.env.NODE_ENV === 'development') {
  const devRoot = document.querySelector('#_marketing-dev-root');

  if (devRoot) {
    mount(devRoot, { defaultHistory: createBrowserHistory() });
  }
}

// We are running through container
// and we should export the mount function
export { mount };

**集装箱: webpack.dev.js**

代码语言:javascript
复制
const { merge } = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const commonConfig = require('./webpack.common');
const packageJson = require('../package.json');
const path = require('path');
const globals = require('../src/variables/global')
const port = globals.port

const devConfig = {
  mode: 'development',
  output: {
    publicPath: `http://localhost:${port}/`,   // don't forget the slash at the end
  },
  devServer: {
    port: port,
    historyApiFallback: {
      index: 'index.html',
    },
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'companiesMod',
      filename: 'remoteEntry.js',
      exposes: {
        './CompaniesApp': './src/bootstrap',
      },
      shared: packageJson.dependencies,
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  resolve: {
    // for dotenv config
    fallback: {
      "fs": false,
      "os": false,
      "path": false
    },
    extensions: ['', '.js', '.jsx', '.scss', '.eot', '.ttf', '.svg', '.woff'],
    modules: ['node_modules', 'scripts', 'images', 'fonts'],
    alias: {
      mdbReactUiKit: 'mdb-react-ui-kit'
    },
  },
};

module.exports = merge(commonConfig, devConfig);

**营销(远程):webpack.dev.js **

代码语言:javascript
复制
const { merge } = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const commonConfig = require('./webpack.common');
const packageJson = require('../package.json');

const devConfig = {
  mode: 'development',
  output: {
    publicPath: 'http://localhost:8081/'   // don't forget the slash at the end
  },
  devServer: {
    port: 8081,
    historyApiFallback: {
      index: 'index.html',
    },
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'marketingMod',
      filename: 'remoteEntry.js',
      exposes: {
        './MarketingApp': './src/bootstrap',
        './FooterApp': './src/components/footer/Footer',
      },
      shared: packageJson.dependencies,
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
};

module.exports = merge(commonConfig, devConfig);

容器: package.json

代码语言:javascript
复制
{
  "name": "containerr",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack serve --config config/webpack.dev.js",
    "build": "webpack --config config/webpack.prod.js"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/theCosmicGame/mavata.git",
    "directory": "packages/containerr"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.3.0"
  },
  "devDependencies": {
    "@babel/core": "^7.18.6",
    "@babel/plugin-transform-runtime": "^7.18.6",
    "@babel/preset-env": "^7.18.6",
    "@babel/preset-react": "^7.18.6",
    "@svgr/webpack": "^6.2.1",
    "babel-loader": "^8.2.5",
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.7.1",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.5.0",
    "sass-loader": "^13.0.2",
    "style-loader": "^3.3.1",
    "url-loader": "^4.1.1",
    "webfontloader": "^1.6.28",
    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3",
    "webpack-merge": "^5.8.0"
  },
  "dependencies": {
    "@emotion/react": "^11.9.3",
    "@emotion/styled": "^11.9.3",
    "@mui/icons-material": "^5.8.4",
    "@mui/material": "^5.9.0",
    "styled-components": "^5.3.5"
  }
}

**营销: package.json**

代码语言:javascript
复制
{
  "name": "marketing",
  "version": "1.0.0",
  "scripts": {
    "start": "webpack serve --config config/webpack.dev.js",
    "build": "webpack --config config/webpack.prod.js"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/theCosmicGame/mavata.git",
    "directory": "packages/marketingg"
  },
  "devDependencies": {
    "@babel/core": "^7.12.3",
    "@babel/plugin-transform-runtime": "^7.12.1",
    "@babel/preset-env": "^7.12.1",
    "@babel/preset-react": "^7.12.1",
    "babel-loader": "^8.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^5.0.0",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^4.5.0",
    "sass-loader": "^13.0.0",
    "style-loader": "^2.0.0",
    "webfontloader": "^1.6.28",
    "webpack": "^5.4.0",
    "webpack-cli": "^4.1.0",
    "webpack-dev-server": "^3.11.0",
    "webpack-merge": "^5.2.0"
  },
  "peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.3.0"
  },
  "dependencies": {
    "@emotion/react": "^11.9.3",
    "@emotion/styled": "^11.9.3",
    "@mui/material": "^5.9.0",
    "styled-components": "^5.3.5"
  }
}
EN

回答 1

Stack Overflow用户

发布于 2022-07-18 15:41:32

在我的webpack.dev.server里,我改变了

代码语言:javascript
复制
shared: packageJson.dependencies,

为了..。

代码语言:javascript
复制
shared: {...packageJson.dependencies, ...packageJson.peerDependencies}

警告就消失了

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73014600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档