aditya81070
aditya81070

Reputation: 736

How to share redux store in micro frontend architecture?

I am trying to create a small project to implement micro-frontend architecture following Micro Frontends article. I am creating multiple repositories for each MFE(Micro frontend) and also using Redux for the application. I have the following architecture:

  1. Frame - A centralised(main) repo that is responsible for rendering the main application part and MFEs based on routing(I am using connected-react-router). It initialises the Redux store and also adds an injectReducer function to dynamically add reducers as explained in code splitting in redux docs. The frame fetches the manifest for particular MFE and renders it. The frame also has some redux data for authentication purpose.
  2. MFEs - These are the individual feature-wise application and are rendered by frame.

Now I have a problem that I want to use injectReducer function into my MFEs to dynamically add reducers to store. For this, I need access to the same store instance that is created by frame. As mentioned in this answer, the ideal way is to export the created store instance and use it but how we can share the same instance of the store across multiple repos?

Upvotes: 13

Views: 25445

Answers (4)

SAIF
SAIF

Reputation: 11

You can use module mederation to share your redux store in microfrontend
Here's how you can do it

To share between MFEs using Module Federation, you expose a module from one micro frontend (MFE) using ModuleFederationPlugin with an exposed path, like './remoteEntry.js'. In the host MFE, you use the remotes property to consume this exposed module, specifying its location. Finally, you import the shared module in the host MFE code, treating it as a local module.

MF-1
/webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "MF1",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        "./store": "./src/Redux/store.ts"
      }
    )]

MF-2
/webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "MF2",
      filename: "remoteEntry.js",
      remotes: {
        MF1: "MF1@http://localhost:8080/remoteEntry.js",
      },
      exposes: {}
    )
  ]

Where you wanna use it

import store from "MF1/store";
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
import "./index.css";

const App = () => {
  console.log(store.getState(), "store");

  return (
    <Provider store={store}>
      <Router>
        // routes
      </Router>
    </Provider>
  );
};

const rootElement = document.getElementById("app");
if (!rootElement) throw new Error("Failed to find the root element");

const root = ReactDOM.createRoot(rootElement as HTMLElement);
root.render(<App />);

Upvotes: 0

Pratik Bhattacharya
Pratik Bhattacharya

Reputation: 3746

You can take a look at this NPM package. This package would allow each Micro Frontend to have its own redux store but allow other Micro Frontends to see and subscribe to state changes of other Micro Frontends.

Github
https://github.com/microsoft/redux-micro-frontend

NPM
https://www.npmjs.com/package/redux-micro-frontend

Article
https://www.codezap.dev/post/state-management-ii-world-of-micro-frontends

Might solve your problem.

Upvotes: 3

Raja S Velagaleti
Raja S Velagaleti

Reputation: 61

Use synthetic events for cross micro frontends communication using eventListeners and CustomEvent like below:

MF-1:

function Cart() {
  const [cartItems, addCartItems] = useState([]);

  const handleAddToCart = (event) => {
    addCartItems((currentItems) => [...currentItems,
    event.detail.item]);
  };

  useEffect(() => {
    window.addEventListener('addToCart', handleAddToCart);

    return () => {
      window.removeEventListener('addToCart', handleAddToCart)
    }
  }, [handleAddToCart]);
  ...
}

MF-2:

function itemLookUp() {
  const handleSubmit = (item) => {
    const customEvent = new CustomEvent('message', { detail: item });
    window.dispatchEvent(customEvent)
  }
  ...
}

Upvotes: 6

Andrew
Andrew

Reputation: 7555

There is a comment in the article addressing this directly:

If you are using redux, the usual approach is to have a single, global, shared store for the entire application. However, if each micro frontend is supposed to be its own self-contained application, then it makes sense for each one to have its own redux store. The redux docs even mention "isolating a Redux app as a component in a bigger application" as a valid reason to have multiple stores.

Long story short: Don't share your redux store

Sharing anything between your micro frontends no longer makes them separate entities and defeats the entire purpose of it. Now it's just an overengineered monolith. Just turn those respective repos into well-defined modules inside a monolith repo. It is still possible to split responsibilities into their own silos in a unified repo. It just takes more discipline.

Upvotes: 14

Related Questions