module-federation / module-federation-examples

Implementation examples of module federation , by the creators of module federation
https://module-federation.io/
MIT License
5.63k stars 1.75k forks source link

How to make container working if one of the microfrontend is down? #1232

Closed arunreddy-kr closed 3 years ago

arunreddy-kr commented 3 years ago

I have a container and two micro frontends developed in react and typescript. I am trying to make container up and running if one of the microfrontend is down. Is there any way to do that? I didn't see that feature being available in the module federation

ChrisHendrX commented 3 years ago

Hey,

Personnaly I wrapped my Microfrontend inside an error boundary : https://fr.reactjs.org/docs/error-boundaries.html In the host App, I load asyncronously the Micro-frontend. If it fails I display an Error component.

ErrorBoundary.jsx

import React from 'react';
import NotFound from 'components/pages/NotFound';
import Loading from 'components/layout/Loading';

const AsyncLoader = ({ children }) => {
  return (
    <ErrorBoundary>
      <React.Suspense fallback={<Loading />}>
        {children}
      </React.Suspense>
    </ErrorBoundary>
  )
};

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    return this.state.hasError ? <NotFound /> : this.props.children;
  }
}

export default AsyncLoader;

Host App :

const MyMicrofrontEnd = loadable(() => import('myMicrofrontend/App'), { fallback: <Loading /> });
const App = () => (
[...]
<Route exact path='/mfe'>
    <ErrorBoundary>
        <MyMicrofrontEnd />
    </ErrorBoundary>
</Route>
[...]
);
arunreddy-kr commented 3 years ago

@ChrisHendrX May I know where did you get the "loadable" function?

ChrisHendrX commented 3 years ago

https://www.npmjs.com/package/@loadable/component It's an alternative of React.lazy If you don't want to use loadable, you can simply import your component with React lazy this way : const MyMicrofrontEnd = React.lazy(() => import("myMicrofrontend/App"))

arunreddy-kr commented 3 years ago

@ChrisHendrX Thanks for pointing me to the @loadable package. I am not seeing AsyncLoader is being used anywhere in your example. What is the use of it? Also, I have the following code in my App.tsx file. Could you let me know how to modify it?

import React, {lazy, Suspense} from 'react';
import ContainerMenu from './components/ContainerMenu/ContainerMenu';
import {ErrorBoundary} from 'react-error-boundary';
import './App.css';
import {Redirect, Route, Switch, Router} from 'react-router-dom';

const MF1AppLazy = lazy(() => import('./components/MF1App/MF1'));
const MF2AppLazy = lazy(() => import('./components/MF2App/MF2'));

const App = () => {
    return (
        <div className="container">
            <ContainerMenu></ContainerMenu>
            <div className="components">
                <Suspense fallback={<div>loading...</div>}>
                    <Switch>
                        <Route path="/" exact>
                            <Redirect to="/mf1"></Redirect>
                        </Route>

                        <Route path="/mf1" component={MF1AppLazy}></Route>
                        <Route path="/mf2" exact component={MF2AppLazy} />
                    </Switch>
                </Suspense>
            </div>
        </div>
    );
};

export default App;
arunreddy-kr commented 3 years ago

@ChrisHendrX Could you guide me on the usage of AsyncLoader code?

ChrisHendrX commented 3 years ago

Hey,

I think I gave you the correct code 🤓

ErrorBoundary.jsx import React from 'react';

const NotFound = () => (

404 Not Found. The remote component has not been loaded !

);

const Loading = () => (

Loading the remote component...

) const AsyncLoader = ({ children }) => { return (

}> {children}

) };

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; }

static getDerivedStateFromError(error) { return { hasError: true }; }

render() { return this.state.hasError ? : this.props.children; } }

export default AsyncLoader;

App.jsx import React from "react"; import { BrowserRouter, Switch, Route } from "react-router-dom"; import AsyncLoader from "the/path/to/ErrorBoundary"; const MyRemoteComponent = React.lazy(() => import("myRemoteComponent/App")); const App = () => {

; }; In the Forum I gave you the same exact code. It's just that AsyncLoader (inside ErrorBoundary.jsx) is exported by default and use the ErrorBoundary component (inside ErrorBoundary.jsx) Whenever you import a component which is exported by default, you can name it whatever you want in the import. So I imported ErrorBoundary but in reality, I imported AsyncLoader from ErrorBoundary.jsx I updated the code above to make it easier for you Hope I helped you ! :) Le mer. 27 oct. 2021 à 17:34, Arun Reddy ***@***.***> a écrit : > @ChrisHendrX Could you guide me on the > usage of AsyncLoader code? > > — > You are receiving this because you were mentioned. > Reply to this email directly, view it on GitHub > , > or unsubscribe > > . > Triage notifications on the go with GitHub Mobile for iOS > > or Android > . > >
arunreddy-kr commented 3 years ago

It worked. Thanks for guiding me. Appreciate the help