9

I currently have multiple React v17 apps which utilise Module Federation from Webpack 5. I would like for my MUI 5 theme to be shared across all of these micro frontends without having a there own ThemeProvider wrapped around each exposed component. At present, APP 1 (Shell) adds a custom theme into the MUI ThemeProvider and all Micro UI's are lazy loaded as children. The custom theme works for the container components but not for the micro frontend components. I am following a micro frontend architecture with the following configuration:

  1. APP 1 (Shell) - Primary role is manage authentication, wrap theme and consume page components from other micro frontends.
  2. APP 2 (Home Page) - Expose page component and rely on theme rendering from shell.
  3. APP 3 (Another page etc..) - Expose page component and rely on theme rendering from shell.

...and so forth for all other micro frontends.

APP 1 - Module federation config:

const { ModuleFederationPlugin } = require('webpack').container
const { shared } = require('./shared/shared')

const homePage = 'https://localhost:8084';

var moduleFedConfig = new ModuleFederationPlugin({
    name: 'container',
    filename: 'remoteEntry.js',
    remotes: {
        homePage: `homePage@${homePage}/remoteEntry.js`,
    },
    shared: shared,
});

APP 2 - Module federation config:

const { ModuleFederationPlugin } = require('webpack').container;
const { shared } = require('./shared/shared');

var moduleFedConfig = new ModuleFederationPlugin({
    name: 'homePage',
    filename: 'remoteEntry.js',
    exposes: {
        './HomePage': './src/page/HomePage',
    },
    shared: shared,
});

module.exports = { moduleFedConfig };

Module federation shared dependencies config for both APP1 & APP2

const deps = require('../../../package.json').dependencies;

var shared = {
    react: {
        singleton: true,
        requiredVersion: '*',
    },
    'react-dom': {
        singleton: true,
        requiredVersion: '*',
    },
    'react-router-dom': {
        singleton: true,
        requiredVersion: '*',
    },
    '@okta/okta-auth-js/': {
        singleton: true,
        requiredVersion: 'auto',
    },
    '@okta/okta-react': {
        singleton: true,
        requiredVersion: 'auto',
    },
    '@reduxjs/toolkit': {
        singleton: true,
        requiredVersion: deps['@reduxjs/toolkit'],
    },
    'react-redux': {
        singleton: true,
        requiredVersion: deps['react-redux'],
    },
    '@emotion/react/' : {
        singleton: true,
        requiredVersion: '*',
    },
    '@emotion/styled' : {
        singleton: true,
        requiredVersion: '*',
    },
    '@mui/material' : {
        singleton: true,
        requiredVersion: '*',
    },
};

module.exports = { shared };

APP 1 (Shell) - Snip of theme provider code:

   React.useEffect(() => {
        const newIsLoaded =
            themeData.elementStyles !== null && themeData.theme !== null
        setIsThemeLoaded(newIsLoaded)
    }, [themeData.elementStyles, themeData.theme])

    return !isLoginRedirect &&
        authState?.isAuthenticated &&
        isThemeLoaded &&
        themeData.theme ? (
        <ThemeProvider theme={themeData.theme}>
            <CssBaseline />
            <AppContainer /> //All micro front end components are rendered within here
        </ThemeProvider>
    ) : (
        <Loading fadeIn />
    )

I would expect that because all the MUI modules are being shared as a singleton, all theme data setup in the initial shell would be accessible in the child micro frontend components.

Just to confirm as well that RTK & RTK Query work perfectly when shared so I suspect I'm missing something when adding a module to be shared for MUI 5 maybe?

If you need anything further then please don't hesitate to ask.

Thank you in advance.

Kitson88
  • 2,889
  • 5
  • 22
  • 37
  • I know that react query has an options to share a singleton version of the context on the window. `contextSharing={true}` Each of the MF's check the window for the context using it if defined and creating it if now. I am not sure MUI has the functionality for the theme context. – Will Aug 31 '22 at 14:51
  • I am facing a similar problem where starting up an MF causes a conflict of some MUI dependencies. This seems to create different instances of the the styling causing some of the components to be styled incorrectly. I feel we have a similar problem so I have added abounty to get more detail – Will Aug 31 '22 at 14:54
  • We have a shared component in a component library that handles the selection of the theme. We store the theme in local storage and each of the MF's looks at that and sets the theme in its own theme provider. Not sure if this is a great solution but we can run the MF's in isolation this way – Will Aug 31 '22 at 15:10

2 Answers2

1

Try adding @mui/system and @mui/styles both with singleton true It should do the job

y-me
  • 277
  • 4
  • 13
0

I was able to resolve the issue by using an MF library called importRemote that lazy loads the components rather than the exposed components being loaded when the shell/container has started.

Kitson88
  • 2,889
  • 5
  • 22
  • 37