module-federation / module-federation-examples

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

How do I share a MUI 5 theme across multiple micro front ends using Module Federation #2198

Closed K1tson closed 2 years ago

K1tson commented 2 years ago

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.

Semigradsky commented 2 years ago

Do you really want to share a theme? When you updated the theme you will need to update all your micro frontends. I use MUI with module federations and I prefer to have micro frontends with their own ThemeProviders.

ScriptedAlchemy commented 2 years ago

Share as @mui/ with the trailing slash on the end of the key