Understanding Micro Frontends With a Hands-On Example Using React, Webpack 5, and Module Federation

Rany ElHousieny
Feb 8 · 12 min read

Micro Frontends have been growing, recently, because of the need to break the Frontend monolith and the success showed in Microservices architecture. However, very few understand the concept or know that it exists. Reading about theoretical concepts makes things harder than they are. Therefore, I decided to explain the concepts with a hands-on project. I love to see things working to understand challenges and how things work. I will be using Webpack 5 and Module Federation Plugin. I hope this is useful for you. As usual, please send me your feedback.

Good frontend development is hard. Scaling frontend development so that many teams can work simultaneously on a large and complex product is even harder.” Martin Fowler

Setup The Development Environment

Prepare your machine and install nodejs, if needed follow the article/video, below:

[Optional] You may create a Github project and clone it (I am using https://github.com/ranyelhousieny/micro-front-ends)

git clone https://github.com/ranyelhousieny/micro-front-ends.git

We will create the following 3 frontends container, micro-front-end-1, and micro-front-end-2

We will use create-react-app to create the 3 base projects as explained in the video, below, but we will call them container, micro-front-end-1, and micro-front-end-2, instead.

The container will orchestrate between multiple micro-front-ends

npx create-react-app container

npx create-react-app micro-front-end-1

npx create-react-app micro-front-end-2

Install dependencies for micro-front-end-1

cd micro-front-end-1

npm install webpack webpack-cli webpack-server html-webpack-plugin

npm install webpack webpack-cli webpack-server html-webpack-plugin

Implement micro-front-end-1

go inside the micro-front-end-1 directory and open the IDE using (code .)

Navigate inside src/index.js

remove all the code in index.js and replace it with

console.log(“micro-front-end-1”);

Use Webpack to bundle the code

A detailed explanation of Webpack configurations can be found in the following article

Let’s create a bundle using Webpack

Create webpack.config.js on the root of the micro-front-end-1

touch webpack.config.js

Now, let’s try to build and see what happens. Run the following command:

npm webpack

You will get few errors. Let’s take one by one.

The first error is asking about the mode. Webpack needs to know which mode to run with to be able to bundle the dependencies, accordingly. Let’s use Development mode. In webpack.config.js add the following

module.exports = {
mode: 'development',
};

This will take care of the first error and tell Weboack to build in development mode. Now, build again and watch the folders on the left hand side. You will notice a destination folder named “dist” will be created.

This is the folder that will be generated by Webpack’s build and bundle process and this is the folder we will deploy to the S3 Bucket. What happened here is that Webpack took all the code we have index.js, bootstrap.js, App.js … and there dependencies and bundled them in main.js as you can see.

Now we do not see the mode error, but we still React and loader errors. Those errors because Webpack needs loaders to understand React. As you know Browser only understand CSS, HTML,, and JavaScript ES5 (for now). JSX and ES6+ will need a compiler. We use babel for that. I will show you how to add those loaders to the configuration but first let’s create a local server to see our demonstrate our website (This will be S3 configured as a website at the end)

add a script to package.json

A new file will be created dist/main.js

Add the Webpack server

To add a local server on a certain port (here, I used 8001), add the following lines to webpack.config.js

devServer: {
port: 8081,
},

Now, run the following command

yarn webpack serve

This will start a local web server on port 8081. However, if you navigate to https://localhost:8081, you will only find alist of files. This is because we did not configure index.html, yet. We will do this in the coming step. However, try to browse main.js and you will be able to see its content as follows:

So far, Webpack created a local web server on Port 8081 as we configured it in Webpack.config.js. However, it is still missing a min component for the browser: index.html

HTML Webpack Plugin

We need to import html-webpack-plugin for Webpack to generate index.html and add the bundled js files to it.

const HtmlWebpackPlugin = require('html-webpack-plugin');

Also, add the html-webpack-plugin to fill the index.html as follows

webpack.config.js up to this step can be found here

Add serve to the script in package.json

remove everything in public/index.html and write the following

from the terminal under the directory of micro-front-end-1, start the script

npm run webpack

Go to the browser and browse HTTP://localhost:8081

right click and inspect to see the output of the console.log

This is the main concept.

Now, let’s display on the page, instead of console

Add the following to index.html

<div id=”root”></div>

Add the following querySelector

document.querySelector(‘#root’).innerHTML = `<h1>Micro-Front-End-1</h1>`

Refresh the browser

So far, we have one component and it is not connected to anything

=====================================

Now, let’s build the container

open another terminal and navigate to the root directory where we had the three apps

Now, navigate inside the container directory

Install dependencies as before.

install webpack webpack-cli webpack-server html-webpack-plugin

Now, let’s navigate back to the root of the three services and open VS code with the three components to work on them at the same time

Copy webpack.config.js from micro-front-end-1 to container and change the port to be 8080 as follows

Change the package.json script the same way we had before (you can copy it from micro-front-end-1

“webpack”: “webpack serve”,

Change index.js and index.html like before but write to the console “container”

run the script (npm run webpack) and check the browser http://localhost:8080/

========================

Connecting Both together

1- Add Module Federation Plugin

in micro-front-end-1/webpack.config.js add the following

This will expose index.js from micro-front-end-1. (Note that we used camelCase)

Now, let’s fetch it from the container

Go to container/webpack.config.js and add the following

container/webpck.config.js up to this point can be found here

now, rename container/src/index.js to container/src/bootstrap.js and import microFrontEnd1/MicroFrontEnd1Index (This is to run the file asynchronously until it gets the data from micro-front-end-1 to the container)

create a new container/src/index.js and import(‘./bootstrap’);

Now restart npm run webpack for both services

First, run micro-front-end-1

ctrl + c

npm run webpack

Second, run the container

ctrl + c

npm run webpack

Add the id to container/public/index.html

Browse the container port 8080 http://localhost:8080/ and you will find the text from micro-front-end-1 present there

Now, let’s understand what we have done.

As you are on the page, select Network, Disable Cache, and Java as shown below:

Refresh the page to send calls to servers and note the output

Right-click on the header next to Name and select Url from the menu to show the URL that has been called.

You will see the following URLs been calls

  1. It first called main.js on http://localhost:8080/main.js . This is the container
  2. Called the remoteEntry.js on http://localhost:8081/remoteEntry.js . This is micro-front-end-1
  3. Back again to the container calling bootstrap
  4. finally calling src_index_js.js from micro-front-end-1 (index.js) to present its output on the screen

All of this came from the ModuleFederationPlugin

webpack used this configuration from micro-front-end-1/webpack.config.js to create http://localhost:8081/remoteEntry.js and http://localhost:8081/src_index_js.js

Then the configuration on container/webpack.config.js told the server how to fetch http://localhost:8081/remoteEntry.js

inside http://localhost:8081/remoteEntry.js the information needed to fetch src_index_js.js

Module Federation Plugin allowed JavaScript to dynamically import code from micro-front-end-1 into the container at runtime.

==============

Adding the second Micro Frontend

Before adding the second Micro Frontend, let’s add more paragraphs to the first one. I like using a tool called Lorem ipsum

You just press F1 and write Lorem ipsum and select how many paragraphs

The new index.js for this step can be found here

Now, repeat the same processes inside micro-front-end-2

  1. Copy webpack.config.js from micro-front-end-1 to micro-front-end-2
  2. Update the names inside it as follows:

Install dependencies for micro-front-end-2

cd micro-front-end-2

npm install webpack webpack-cli webpack-server html-webpack-plugin

Add the webpack script to package.json

run npm install from inside micro-front-end-2 folder

Erase the content of micro-front-end-2/public/index.html and copy into it micro-front-end-1/public/index.html content. replace the id with a new id as follows

Erase the content of micro-front-end-2/src/index.js and copy into it micro-front-end-1/public/index.html content. replace the id with the one you had above and the name of the service in the <h1> tag as follows

Now, run npm run webpack

Now navigate to http://localhost:8082/

Now, connect it to the container

in container/webpack.config.js add another remote as follows

microFrontEnd2: ‘microFrontEnd2@http://localhost:8081/remoteEntry.js',

in container/src/bootstrab.js add the following import

import ‘microFrontEnd2/MicroFrontEnd2Index’;

in container/public/index.html add the id for micro-front-end-2 in the space you want. I added it as follows

restart webpack for the container and navigate to http://localhost:8080/

No, if you inspect the network traffic you will find calls to both servers

=================================

So far, we have not used React. In the following article, we will add a third micro frontend, react-microfrontend-3

Learn More

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/. Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

Rany ElHousieny

Written by

https://www.linkedin.com/in/ranyelhousieny Commercial software development manager offering 25+ years of technical experience. Certified Solutions Architect

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/. Don’t forget to check out Ask-NFT, a mentorship ecosystem we’ve started

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store