What is Module Federation?
Module Federation is a Javascript architecture of using reusable components between multiple applications. I might have just made it sound effortless, but it indeed is very simple jargon. As we are all aware of sharing components within a React application, Module Federation is essentially doing the same thing under the hood, except it exposes modules within an application to be consumed by a different application dynamically.
Before we try out Module Federation in two different Next.js applications and boil down how it is implemented, I would like to explain another term that you might come across often. And, it is called Micro-frontend.
Micro-frontend architecture is a design approach in which a front-end app is decomposed into individual, semi-independent “microapps” working loosely together. - Bob Myers
Module Federation
Very simply, micro-frontend allows multiple development teams to work on the same front-end application. The decomposed "micro-apps" can be maintained separately as they are de-coupled, which also means that they can be developed and deployed independently.
Some more information
There are couple of terms that we need to define before we can move further ahead.
- Host: A host is a build/module initialized first during a page load. A host can be termed as a provider.
- Remote: A remote is another build that consumes some part of the host. They can also be referred to as consumers.
Note: All applications can be both remote and host, providers, and consumers of any other federated module in the system.
Furthermore, we need to know another concept of overriding modules. For example, if you're importing a React component that ships along with the entire React code, the local build won't download the React code again, instead it will overwrite the React code and only import the essential component code. This helps the local build to avoid downloading the already existing dependencies.
Why Module Federation?
- All we had in a while were externals and DLLs (Dynamic Link Libraries) to share functionalities between applications. All of which made code sharing very hard and difficult to scale.
- Inconvenience - When two independent applications critically share critical code they needed to be adaptive and dynamic.
- NPM is slow.
- Module Federation was designed so that standalone applications could entirely be in their own repository, deployed independently, and run as its own independent SPA.
Let us try out Module Federation
We are going to have two different Next.js applications for the demonstration. One of which will be a provider or a build that exposes modules to be consumed and the other one would import a component from the consumable build. Just to give you a background if you haven't already used Next.js, Next.js is essentially a React front-end framework that provides tons of new features like Server-side rendering and Static Site Generation on top of the React ecosystem.
Setting up the application
Create a root directory that will contain both of our applications. Inside the directory, we will have two different independent Next.js applications.
Let's go ahead and create the first application that will be our host. Just to make naming conventions a bit simple we will name the application as home. Go ahead and create the Next.js application.
This command will create us a Next.js application inside the home directory. Our first application requires a few more tweaks before we can make use of the Module Federation. These configurations are manual and we will run through them step-by-step.
Home being our first application it will be sharing out a component to our second application that we will be building sometime later.
Manual setup (First Next.js application)
Go ahead and install the module federation npm package like so.
And within the package.json
include the following resolution to use a specific version of the webpack.
We now need to manually clean up the node_modules folder to reflect the changes. Go ahead and remove the node_modules folder and then re-install it again.
Once we have all of our packages installed, we now need to create a config file called next.config.js
to enable the Home application to expose a consumable component.
Go ahead and paste the code below inside the next.config.js
file. All this config does is, require the module-federation npm package and helps us expose the consumable component inside the "exposes" object.
After we are done with the config file, we now need to include a custom document that will help us override the default settings of our Next.js application. The way we do that in the Next.js application is to create a _document.js
file inside the pages directory of our Home application.
Copy the code below into the _document.js
file. The file will enable patchSharing()
which will help us share some part of the code with some other application.
Now the next step is to actually create the component that we will share with another application. Inside the home directory create a new folder called components and include a file called Header.jsx
inside of it. The Header component will have a colored div and some text inside it. It wouldn't be an extra-ordinarily fancy component but one that serves the purpose.
Now go ahead and copy the following code inside the Header component that we just built:
The only way to show up this component on our application is to import it inside the index.js file which is the entry point of our Next.js application. Go ahead and import the component like so:
We have one more step before we can create our second application. We need to export the Header.jsx
component inside the "exposes" object that we defined earlier inside the next.config.js
file.
Second Next.js application
Now go ahead and create the second application. You can probably call it whatever you want, but for the sake of this demonstration, I would call it remote. Make sure you are in the root directory (mf-next), and then spin up another Next.js application using the following command.
While you installed the nextjs-mf
package globally you now have access to a CLI (command-line interface). You need to upgrade the port number of the second application (or the remote), to run both the applications concurrently (home and remote).
The above command will upgrade the port to 3001 (to avoid port clashes) and it will automatically scaffold the next.config.js
file for you. All you need to do is uncomment out whatever is in the "remotes" object with the key set to home (or whatever the name of your first application is). The file will look something like this:
Notice you will also have a _document.js
inside the pages directory. Uncomment the script tag within the render method. The script tag is a special entry point (a few KB's in size). They contain a special webpack runtime that can interface with the host (or home in our case).
In the index file of our remote app, we now import the Header component and render it within the second application. You now need to run both the development servers and there you go you now have a Next.js application (home) that exposes a consumable component which is then consumed by the second Next.js application (remote). I've put up a snapshot of both the applications below for you to demonstrate what we will have after following all the steps above.
application demo
Any changes to the home application will now reflect it back on the remote application. How cool is that? That is Module Federation for you.
Conclusion
Module Federation has some great features like avoiding dependency duplication (built-in redundancy). Since remote builds are dependent on hosts, if the host does not ship dependencies that the remote requires, the remote can download the missing dependencies on its own. Module Federation being started out as a Javascript architecture was moved on to support as a Webpack plugin. It certainly changes the scene of building scalable applications using micro-frontends. There are tons of in-depth blogs about Module Federation. If you are rather interested on watching a video I would suggest you to go ahead and watch Jack Herrington's Youtube on Federated Modules in Webpack 5. The link will be attached below. Additionaly, if you want to read in-depth about Module Federation I would highly recommend you to visit the links below.
- Module Federation - Blog by Zack Jackson (Creator of Module Federation)
- Module Federation Concepts - Webpack.js
- Federated Modules - Jack Herrington
- Complete code of the tutorial can be found here.