Nothing Special   »   [go: up one dir, main page]

DEV Community

Shashank Trivedi
Shashank Trivedi

Posted on

Webpack 5 series part-4

Please look for the other parts of the series to fully understand the concept.
Webpack 5 series part-1
Webpack 5 series part-2
Webpack 5 series part-3

Shared state management in Microfrontend

In a micro-frontend architecture, managing shared state between multiple micro-frontends can be challenging, but it can be done in a few ways.

  1. Using a Shared State Library (Global State)
  • Redux / Zustand / Recoil: These libraries allow you to manage a global state that can be shared across multiple micro-frontends. You can create a separate micro-frontend responsible for managing the global state (like a store), and expose that state using Webpack's Module Federation.

  • With Module Federation, you can share libraries like Redux between micro-frontends. You need to ensure that the global store is accessible to all the micro-frontends that need to share state.

new ModuleFederationPlugin({
  name: 'app1',
  remotes: {
    store: 'store@http://localhost:3001/remoteEntry.js'
  },
  shared: ['react', 'react-dom', 'redux'],
})
Enter fullscreen mode Exit fullscreen mode
  1. Custom Event System or Event Bus
  • Use an event-driven architecture where micro-frontends communicate by dispatching and listening to events (custom events). This is a decoupled approach and prevents tight coupling between micro-frontends.

  • You can implement this using JavaScript's CustomEvent or a more sophisticated event bus.

const event = new CustomEvent('sharedStateChange', { detail: { data } });
window.dispatchEvent(event);
Enter fullscreen mode Exit fullscreen mode
window.addEventListener('sharedStateChange', (event) => {
  console.log('Received data:', event.detail.data);
});
Enter fullscreen mode Exit fullscreen mode
  1. Context API with Module Federation

If you are using React, you can use the Context API to manage shared state across micro-frontends. One micro-frontend can provide a context, and others can consume it.

Example:

  • Provider Micro-frontend: Provide the context and expose it using Module Federation.

  • Consumer Micro-frontend: Import the exposed context and consume it.

  1. Shared Services or APIs

Have a centralized API or service layer that all micro-frontends can communicate with to get or update shared state. This can be a service in a backend or an in-browser shared state service.

For example, you could implement a simple shared service like this:

class SharedStateService {
  constructor() {
    this.state = {};
    this.subscribers = [];
  }

  getState() {
    return this.state;
  }

  setState(newState) {
    this.state = { ...this.state, ...newState };
    this.notifySubscribers();
  }

  subscribe(callback) {
    this.subscribers.push(callback);
  }

  notifySubscribers() {
    this.subscribers.forEach(callback => callback(this.state));
  }
}

const sharedService = new SharedStateService();
export default sharedService;

Enter fullscreen mode Exit fullscreen mode

All micro-frontends would import this service and subscribe to state changes.

  1. LocalStorage / SessionStorage
  • For less complex or smaller-scale use cases, LocalStorage or SessionStorage can be used to persist shared data across micro-frontends. When one micro-frontend updates the state in LocalStorage, the others can read from it.

  • This approach works well if you need to persist the state temporarily or across page reloads but can become cumbersome with more complex applications.

Tips for Working with Micro-Frontends:

  • Avoid Global State When Possible: Keep state local to each micro-frontend when possible to reduce coupling.

  • Use Well-defined Interfaces: Define clear contracts between micro-frontends to avoid unexpected behaviors.

  • Lazy Loading: Use lazy loading for shared dependencies to improve performance.

  • Versioning and Compatibility: Ensure that shared dependencies are versioned correctly to avoid conflicts between micro-frontends.

  • Isolation: Each micro-frontend should be as isolated as possible (style, state, logic) to avoid side effects across different parts of the app.

Top comments (0)