Module Federation is a plugin from Webpack 5 that helps to orchestrate micro-frontend architecture, thereby making it easier for organizational teams to decouple and share applications.
If you have a big monolith on frontend with react, you probably have redux to share info between components. What happens if we have to move some of those components to a module?
Introduction
This post discusses how to share info between modules via redux, so we’ll focus on how modules and base will work with the store, reducers, and actions. Also, the following sections will explain how modules can work with redux as isolated applications or a federated module with minimal code changes.
Index
- Basic app architecture
- Store for base and modules
- Trigger an action from module
- Inject reducer from module to base
- Conclusions
Basic app architecture
In general, this approach consist of:
- A NextJS project as a host/base project.
- Federated modules for some features, such as Header, Homepage, Cart, and ProductPage.
Keep in mind that for this example we’ll be working with an NextJS base (React, Redux, etc) and a module with the same technologies (which exports only one component).
Our module will consist of a web app with react and redux, without NextJS, but the main point here will be only how to interact with redux.
Store for base and modules
The idea here is that all modules should work as an isolated app and as a federated module. Furthermore, we know redux actions can only be triggered under a redux provider.
Therefore, the strategy is to place a provider on sub apps, but export only the components under this provider to inject the module on our base.
The idea is to always have a redux provider, but avoid having two providers when a module is injected.
With this we’ll be able to trigger actions from modules, so no matter if is working as isolated or module.
Trigger an action from module
To trigger an action on Module, we can do it exactly as we do it on any react-redux app. There are only few things to keep in mind:
- When we export a component to work as a module, we are exporting the component and not the reducers, so if we want to have same reducers on base and module, we need to inject it. As que saw in the last image, the exported component will have different provider depending how we work with it.
- If we need a reducer and we don’t want to inject it because we have it from the beginning on the app, we have to search a way to export the reducer from module an include it on base to add it to the store when necessary, avoiding to have the same duplicated reducer on base and module.
- We don’t need to change anything to trigger an action, but the available reducers will depend on where the component is mounted. If it's working isolated, we’ll need to mock or recreate the reducers that we need from base. If is working as module on base, we’ll need to add the reducers that we have on sub-app.
- For testing you'll have to import or mock as in the point 3
Inject reducer from module to base
If you're working on big react app with redux, you probably faced the reducer injection:
const injectAsyncReducer = (store, name, asyncReducer) => {
store.asyncReducers[name] = asyncReducer;
store.replaceReducer(createReducer(store.asyncReducers));
}
You probably wrote a function similar to this, and that code will work perfectly for both of the cases that we're managing here: working isolated and as a module. Why? because in the two cases we'll have a redux provider, the only difference will be that each case will inject the reducer in a different store, but you'll have nothing to deal with.
NOTE: Yes, you can inject redux-sagas as well, if you're curious about I drop this line here
Conclusions
If you were worried about split your monolith in federated modules due to redux, there's nothing to be afraid. The most complicated part probably will be the Webpack configuration and not the redux.
Thank to english.with.yama@gmail.com for proofreading the article.
Top comments (1)
What about github.com/microsoft/redux-micro-f... ?
I find it more convenient to use several stores than one and the feature with eager subscriptions (github.com/microsoft/redux-micro-f...) makes it possible to subscribe to some store even it haven't been configured yet.
Reducer Manager pattern (redux.js.org/usage/code-splitting#...) can lead to known messy consequences.
Also you can namespace your local store: