React Micro frontends with Module FederationReactMicrofrontendswithModuleFederationReactMicrofrontendswithModuleFederation
Matteo Pietro Dazzi
16 Nov 2022
Share
Understand what Micro Frontends are and why Module Federation is useful
The idea behind micro frontends is to think about a website or web app as a composition of features which are owned by independent teams. Each team has a distinct area of business or mission it cares about and specialises in. A team is cross-functional and develops its features end-to-end, from database to user interface.
Micro Frontends 101
Micro frontends are an emerging architecture inspired by microservices. Building with micro frontends is a modern strategy for deconstructing a monolithic codebase into smaller parts, in an effort to increase the autonomy of each team and the delivery throughput. Each part can be considered a micro frontend, which will be deployable independently of the others. In this post, we will be looking at building a React application that leverages micro frontends with module federation.
Micro Frontend Approaches
Before deconstructing the monolith, you should choose the right approach to split your pages. This is useful to understand better and segregate the domain of your application (e.g. login page, private area…). The most common approaches are vertical split (page-based) and horizontal split (parcel-based).
Micro Frontend Approach: Vertical Split
A vertical split approach is the easiest as it allows you to have only one micro frontend at a time on each page. This results in the closest developer experience to a Single Page Application in terms of tools, patterns, and best practices, which remain the same.
Micro Frontend Approach: Horizontal split
A horizontal split allows you to have multiple micro frontends at a time in each view. Usually, it is the most common strategy in business domains with multiple reusable parts.
Micro Frontends Composition
Once you have chosen the right split strategy and created your micro frontends, there is one last thing to do: decide how to compose them. The available techniques are client-side, edge-side, and server-side.
Composing Micro Frontends: Client-side
In client-side composition, each micro frontend is dynamically assembled by the client (e.g. the browser). There are different ways to implement this:
using frameworks, like SingleSPA or Qiankun for Single Page Applications, or Luigi for iframes;
using Module Federation.
Composing Micro Frontends: Edge-side
In edge-side composition, each micro frontend is assembled by the edge (e.g. CDN) using the Edge Side Include (ESI) specification. It is not supported by all the CDNs, and each vendor (Akamai, CloudFlare, Fastly…) behaves differently.
Composing Micro Frontends: Server-side
In server-side composition, each micro frontend is assembled by the server. Even in this case, there are ways to implement it:
The primary use case for module federation is the distribution of software at runtime, with additional support for fallbacks. It works on both client and server. Although it was born as a WebpackPlugin, now communities are trying to implement the same principles for the other bundlers (Rollup, Vite…).
Common Module Federation Terminology
Here is a list of terms commonly used, that will be useful to better understand the rest of the article:
Host
The host is an artefact that includes the initial chunks of our application, the ones that will be used to bootstrap it. The bootstrap phase is pretty common, and starts once the window.onload event has been triggered. The biggest difference lies in the management of the components: normally they are included in the application bundle, increasing its size. With module federation, they are not embedded in the bundle but are just referenced to a remote.
This allows us to have a smaller bundle size and a reduced initial load time. Note that as an application has multiple dependencies, a host can also have multiple remotes.
Remote
The remote is an artefact that provides the code to be consumed by the host. The provided code can be both shared components or common dependencies which will be used by different hosts.
Bidirectional host
The bidirectional host is an artefact that can be both a host or a remote, consuming other applications or being consumed by others .
Federated
The federated objective applies to the code which uses the module federation.
A Real World Scenario
Now, we are going to create an example project to replicate the scenario of the following picture:
In this scenario, we have a host called application, a bidirectional host called components, and a remote called loading. In plain English: firstly, the remote will expose a single loading component. Secondly, the bidirectional host will import the loading component, apply some CSS and then re-expose it. Additionally, it exposes a rounded button.
Finally, the host will include these two components that will be shown to the user. Before diving into the code, you should know that:
this example uses a horizontal split with client-side composition;
each package in the monorepo has been generated using create-react-app and then extended with craco to override the Webpack configuration using a dedicatedplugin that reads and applies the module federation configuration of each package;
although the provided code is organised as a monorepo, the same idea works with multiple repos or any other kind of development strategy;
each federated module can be used as an independent React application.
We are sure this is a host because we are defining just the remotes to import. Please also note the absence of the filename configuration;
it loads its dependencies from a remote called components, which entry point is reachable at the address http://localhost:3001/components.js;
each dependency defined in the package.json will be shared with the other federated modules.
Additionally, we ensure that a specific version of react and react-dom are instantiated just once.
In the end, this is what the user will see:
Module Federation: the Trade-Offs
Applying module federation we have found some trade-offs, which will be explained below:
Pros
Exposing parts of the application in such a dynamic way allows us to have:
faster builds as there is less code to process inside a single package;
more rapid deployments because there are fewer artefacts to release;
more immediate rollbacks because we only have to re-expose the old federated artefact to deploy an old version of the application.
Cons
Module federation is a panacea that can be used everywhere, you must know the shape of your application really well to apply it correctly. As you can see, it also requires a little bit of configuration, which might not be so familiar to developers that have always worked with SPA.
Risks
Without a proper study of the size of each remote or bidirectional host, the final result can be compromised due to the high number of network calls to retrieve each JavaScript file. You should avoid creating lots of small files.
But wait - there's more.
Nearform publishes real-world learnings on data & AI, engineering, and digital strategy - with more merged in weekly.
Insights
Perspectives on AI in engineering, product development, and strategy, for enterprise executives.