Click here to Skip to main content
15,867,568 members
Articles / Web Development / Node.js

Introduction to Microfrontend using ModuleFederationPlugin

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
11 Nov 2022CPOL6 min read 5.9K   1  
An overview of MFE and how module federation plugin helps to build MFE in React
This article is about to build your first MFE using react module federation plugin. To do that, this article gives a walkthrough of what is MFE and what is module federation.

Introduction

This article provides you with an introduction to module federation plugin and provides basic understanding of ModuleFederationPlugin.

We will be addressing the following:

  • Why we need MFE (Micro Frontend)
  • What is MFE (Micro Frontend)
  • How to build MFE (Micro Frontend)

Background

Let's understand the 'Why' part with a story. Amey lives in Thane, India. Thane is known as the city of lakes. One fine day, Amey wants to start his business of selling mobiles. He decides to open 3 stores at 3 popular locations in Thane. The first one is Thane-Highway, the second one is Thane-Lake and last but not the least one is Thane-University. Humm... very good thought. He ran a server before opening shops and noticed that Thane-Highway has demand for Samsung Mobiles, Thane-Lake has demand for IPhone Mobiles, Thane-College has demand for Samsung as well as IPhone. Amey decides to open 3 shops and a website for them.

The first shop has Samsung Mobiles list for customers.
The second shop has IPhone Mobiles list for customers.
The third shop has IPhone and Samsung Mobiles list for customers.

Like every other businessman, he wants to launch the site as soon as possible and he called his friend and asked him to build a website. His friend suggested two approaches for the same. Note that all our applications are fake with no backend integration.

1) Build a Monolithic Application

This approach is good in itself but has potentially a team building an entire application and as business grows with different brands, the website become more and more complex to scale, modify by having tight coupling between components. Also site will bind to a language like react or view, etc. in future if we want to write futuristic code in different language, there is less scope for the same and will majorly require rewriting the entire website.

2) Build (MFE) Microfrontendarchitecture

What is MFE?

Microfrontend help us break large frontend applications into smaller independent applications or modules.
Each smaller application or module responsible for distinct feature of the application.
We can have septate engineering team owning each distance feature of the application.
Each smaller application is easy to understand and make changes.

Build Time Integration

This can be achieved by building Samsung mobile node package and iPhone mobile node package and publishing it through the NPM (Node Package Manager). And build host application that consumes them. Looks better. As these node packages are downloaded and source code is exposed before we load our host application into browser or before source code gets compiled, this approach is known as build time integration.

Run-Time Integration

This can be achieved by building each domain, i.e., Samsung mobile and iPhone mobile as a separate SPA (single page application) known as remote application. Then building host application which hosts these remove applications. As you run your host application, which downloads remote source code and gets access to it. This integration is known as run time integration.

Note: If you do not get it at this point of time, do not worry, stay with me.

How Can We Achieve This?

This can be easily achieved using the ModuleFederationPlugin offer by webpack 5 and above.

Let's me take you to the how part of the story and this started becoming interesting. Download the attached code. It has three applications. Samsung and IPhone are the remote applications and amey-store is the host application.

What is Remote Application?

These applications allow you to share distinct feature (code) with the host application.

What Is the Host Application?

This application controls when and where to show distinct feature share by the remote application.

Walk through of remote application. Open Samsung application. You will notice simple node application having mobilelist.js, loading fake list of mobiles and hosted through index.js where index.js loads to the s-mobile list div in index.html file. Core part is webconfig. If you open webconfig, you will notice the below code.

JavaScript
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
    new ModuleFederationPlugin({
      name: 'samsungmobiles',
      filename: 'remoteEntry.js',
      exposes: {
        './ShowMobiles': './src/index',
      },
    }),

ModuleFederationPlugin for remote application can be configured using three important options name, filename and exposes.

  • name: Remote application must have a name that can be referenced in host application.
  • filename: Bundle file created by webpack that can be downloaded by host application.
  • exposes: component which code we want to share with host. We can give Alisa to the expose component which is a meaningful name that can be imported in host application. If host application asked for ShowMobiles, it give index file from src folder.

Walk through of host application. Open amey-store host project. ModuleFederationPlugin for host application can be configured using option remotes where name is optional but good to give for clarity.

remotes List of project that host can search to get additional code. Consider the below code where if we have import { abc } from 'samsungmobiles'. Then webpack search for the samsungmobiles component within the node module if he does not find it. It goes and checks the same within the ModuleFederationPlugin remotes object. Now if I want to import it like import { abc } from 'samsungmobilesApp', then I can rename my remote entry to:

JavaScript
remote: { samsungmobilesApp: ''samsungmobiles@http://localhost:8081/remoteEntry.js'' }

Value of the remotes property has 'reference name @remote URL'. reference name is nothing but name given to the ModuleFederationPlugin with in remote application. Then comes the URL of host application to download remoteEntry.js file.

JavaScript
new ModuleFederationPlugin({
      name: 'container',
      remotes: {
        samsungmobiles: 'samsungmobiles@http://localhost:8081/remoteEntry.js',
      },
    })

Let go into details how this work. Open bootstrap.js. You will notice the below code.

JavaScript
import 'samsungmobiles/ShowMobiles';
console.log('Host!');

Our index.js load bootstrap.js in async mode import('./bootstrap'). And when bootstrap.js get loaded, it finds the import statement and tries to search package in node module folder. If it does not find that package in node module folder, it goes to the ModuleFederationPlugin and searches the remote section for the samsungmobiles. When it finds that, it downloads remoteEntry.js from the specified url. If you asked what is the use of name before the @ symbol in our case 'samsungmobiles@http://localhost:8081/remoteEntry.js'. If you open the remoteEntry.js, it has variable name samsungmobiles which exposes the code share by the remote application. Let's change this name to samsungmobilesApp as below:

JavaScript
remotes: { samsungmobiles: 'samsungmobilesApp@http://localhost:8081/remoteEntry.js', }, 

Code breaks, this can be fixed by changing remote application (Samsung application) ModuleFederationPlugin name to samsungmobilesApp. When we load component ShowModbiles, all its dependencies also get loaded along with that. In our case, we use faker module to get mobiles names. As both the applications use the same version of fake, we can define it as share dependency. i.e., host application can only load one copy of the dependency and share with all the remote applications.

JavaScript
new ModuleFederationPlugin({
     name: 'container',
     remotes: {
       samsungmobiles: 'samsungmobiles@http://localhost:8081/remoteEntry.js',
     },
     shared: ['faker'],
   })

Host application might be using some dependency, e.g., react package and expect the same version should be use by all the remote applications. In that case, dependency can be specified as singleton. The below code forces all remote applications to run on fake version 5.1.0.

JavaScript
new ModuleFederationPlugin({
     name: 'container',
     remotes: {
       samsungmobiles: 'samsungmobiles@http://localhost:8081/remoteEntry.js',
     },
     faker: {
       requiredVersion: '5.1.0',
       singleton: true,
     },
   }),

Note: The code for the second remote app in our case IPhone application is not given. You can copy the same code as Samsung application for it as self practice.

Points of Interest

This article introduces to MFE using ModuleFederationPlugin. Please stay tuned. I will be discussing the advanced concepts of state management, authentication and CSS handling in the next article.

History

  • 10th November, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer Lionbridge
India India
Amey K Bhatkar, a “Microsoft .Net” Web Developer.
I am programmer by will and profession.
I have completed my MCA in 2011 and join software industry.
Presently I am working with Lion Bridge Technologies in Mumbai - India

Comments and Discussions

 
-- There are no messages in this forum --