NashTech Blog

The Power of React Micro Frontend 

Table of Contents
microfrontend image

Introduction

In this article, you’ll find a comprehensive guide to implementing React Micro frontend. It explains the React Microservices Architecture, the advantages of building monolithic applications using React Micro frontend, various implementation methods, and offers a detailed tutorial for creating Micro frontend with React. 

Introduction to React Micro Frontend  

The traditional monolithic architecture, long prevalent in software development, is gradually being replaced by microservices as an alternative strategy. While the success of the monolithic approach has a strong historical basis, newer, more advantageous technical advancements are emerging. 

The concept of React micro frontend architecture isn’t entirely new; it builds upon earlier architectural patterns. The rise of disruptive trends in social media, cloud computing, and the Internet of Things has significantly influenced the adoption of microservice architecture. 

Thanks to the move towards continuous deployment, businesses can benefit from React micro frontends in several ways, including enhanced scalability, swift deployment, technology independence, reduced isolation faults, efficient upgrades and migrations, high deployability and automatability, decreased security risks, and improved reliability, all leading to reduced development time and increased appeal to engineers. 

Building Micro Frontend with React 

Now, let’s delve into a detailed tutorial on building React Micro frontend. The tutorial will guide you through the process of creating two applications: a host and a remote. The host application will serve as the primary app, while the remote app will act as a sub-app that plugs into the main one. 

We’ll start by creating a basic React app using create-react-app. 

1. In Your Root Directory 

npx create-react-app host-app 
npx create-react-app remote-app 

This will create two apps for you: 

1. host-app/ 
2. remote-app/ 

2. Adding Dependencies 

Within each host-app/ and remote-app/ run: 

npm install –save-dev webpack webpack-cli html-webpack-plugin webpack-dev-server babel-loader css-loader 

This will install webpack & dependencies that we need for webpack configuration. 

NOTE:-Webpack Module Federation is available in version 5 and above of webpack. 

After adding dependencies we can host our app. 

3. Hosting the App 

Let us start with our webpack configuration 

Create a new webpack.config.js file at the root of host-app/ & remote-app/: 

//host-app/webpack.config.js 
const HtmlWebpackPlugin = require("html-webpack-plugin"); 
 
module.exports = { 
entry: "./src/index", 
mode: "development", 
devServer: { 
port: 3000, 
}, 
module: { 
rules: [ 
{ 
test: /\.(js|jsx)?$/, 
exclude: /node_modules/, 
use: [ 
{ 
loader: "babel-loader", 
options: { 
presets: ["@babel/preset-env", "@babel/preset-react"], }, 
}, ], }, 
{ 
test: /\.css$/i, 
use: ["style-loader", "css-loader"], 
}, 
], 
}, 
plugins: [ 
new HtmlWebpackPlugin({ 
template: "./public/index.html", 
favicon: "./public/favicon.ico", 
manifest: "./public/manifest.json", 
}), 
], 
resolve: { 
extensions: [".js", ".jsx"], 
}, 
target: "web", 
}; 
// remote-app/webpack.config.js 
const HtmlWebpackPlugin = require("html-webpack-plugin"); 
const path = require("path"); 
 
module.exports = { 
entry: "./src/index", 
mode: "development", 
devServer: { 
static: { 
directory: path.join(__dirname, "public"), 
}, 
port: 4000, 
}, 
module: { 
rules: [ 

test: /\.(js|jsx)?$/, 
exclude: /node_modules/, 
use: [ 

loader: "babel-loader", 
options: { 
presets: ["@babel/preset-env", "@babel/preset-react"], 
}, 
}, 
], 
}, 

test: /\.css$/i, 
use: ["style-loader", "css-loader"], 
}, 

test: /\.(gif|png|jpe?g|svg)$/, 
use: [ 

loader: "file-loader", 
options: { 
name: "[name].[ext]", 
outputPath: "assets/images/", 
}, 
}, 
], 
}, 
], 
}, 
plugins: [ 
new HtmlWebpackPlugin({ 
template: "./public/index.html", 
favicon: "./public/favicon.ico", 
manifest: "./public/manifest.json", 
}), 
], 
resolve: { 
extensions: [".js", ".jsx"], 
}, 
target: "web", 
}; 

This basic webpack example is to get our js and jsx code transpiled using babel-loader and injected into an HTML template. 

Change the start script in package.json to utilize our webpack config:- 

 
"scripts":{ 
"start": "webpack serve" 
index.js(same for both apps) 

First, we need the index.js as an entry to our app. Another file we are importing is bootstrap.js which renders the React app. 

We need this extra layer of indirection because it will give Webpack a chance to load all of the imports it needs to render the remote app. 

Otherwise, you will see an error like this: 

The shared module is not available for eager consumption 

//host-app/src/index.js 
//remote-app/src/index.js 
import("./bootstrap"); 

Note: It is important to import bootstrap file dynamically using import() statement otherwise you will see the same error. 

 bootstrap.js(same for both apps) 

Next, we define the bootstrap.js file for both repos that renders our React application. 

import React from "react"; 
import ReactDOM from "react-dom/client"; 
import App from "./App"; 
 
const root = ReactDOM.createRoot(document.getElementById("root")); 
root.render( 
<React. Strict Mode>
< App />
</React.StrictMode>
); 
 
App.js(In host App) 

Now we can write our App.js file where the app’s main logic happens. Here we will load two components from remote which we will define later. 

import(“Remote/App”) will dynamically fetch the Remote app’s App.js React component. 
Add Module Federation(In host App) 

We’re not ready to run the app just yet. Next, we need to add Module Federation to tell our host where to get the Remote/App and Remote/Button components. 

In our webpack.config.js we introduce the ModuleFederationPlugin: 

Add the following code to the plugins. 

/ host-app/webpack.config.js 
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 
const { dependencies } = require("./package.json"); 
 
module.exports = { 
//... 
plugins: [ 
new ModuleFederationPlugin({ 
name: "Host", 
remotes: { 
Remote: `Remote@http://localhost:4000/moduleEntry.js`, 
}, 
shared: { 
...dependencies, 
react: { 
singleton: true, 
requiredVersion: dependencies["react"], 
}, 
"react-dom": { 
singleton: true, 
requiredVersion: dependencies["react-dom"], 
}, 
}, 
}), 
], 
}; 
Key Points to Remember: 

Name: This identifier is used to distinguish various modules from one another. 

Remotes: This section defines the federated modules that the application aims to utilize. The “Remote” is designated as the internal name, enabling the components to be loaded using the import(“Remote/”) syntax. Additionally, the location of the remote module’s definition is specified as “Remote@http://localhost:4000/moduleEntry.js.” This URL provides three critical pieces of information: the module’s name (“Remote”), its host location (“localhost:4000”), and the module definition (“moduleEntry.js”). 

Shared: The “Shared” section facilitates the sharing of dependencies across modules. This is particularly crucial for React, as it operates with a global state, allowing only one instance of React and ReactDOM in each application. To ensure this in our architecture, we instruct webpack to treat React and ReactDOM as singletons, utilizing the first version loaded from any module for the entire application, provided it meets the specified “requiredVersion.” Additionally, we import other dependencies from the package.json file, reducing the occurrence of duplicate dependencies across modules. 

Upon executing “npm start” within the host app, the output becomes visible on the screen. This indicates that the host app is successfully configured. However, the remote app currently doesn’t expose any content, so we need to configure it accordingly. 

For the Remote App: 

Let’s begin by setting up the webpack configuration file, leveraging our knowledge of Module Federation from the host app: 

Include the following code snippet in the plugins section. 

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin"); 
const { dependencies } = require("./package.json"); 
 
new ModuleFederationPlugin({ 
name: "Remote", 
 
filename: "moduleEntry.js", 
exposes: { 
"./App": "./src/App", 
"./Button": "./src/Button", 
}, 
shared: { 
...dependencies, 
react: { 
singleton: true, 
requiredVersion: dependencies["react"], 
}, 
"react-dom": { 
singleton: true, 
requiredVersion: dependencies["react-dom"], 
}, 
}, 
}), 

The important things we can note from the above code are: 

  • Our webpack dev server runs at localhost:4000 
  • The remote module’s name is Remote 
  • The filename is moduleEntry.js 
  • Combining these will allow our host-app to find the remote-app’s code at Remote@http://localhost:4000/moduleEntry.js 

Conclusion

While the developer advises against creating a React micro frontend app using the create-react-app command, we trust that this tutorial has provided valuable insights. 

Several key factors have played a pivotal role in driving the adoption and momentum of micro frontend architecture. A large majority of product-oriented businesses leverage this architecture to expedite development and reduce costs. Looking ahead, monolithic designs may primarily serve for prototyping new products, with micro frontend architectures, known for their modularity and scalability, taking center stage in mainstream development. 

For more such posts, please follow our LinkedIn page- FrontEnd Competency.

Picture of Anuj

Anuj

As a skilled web developer, I specialize in React and Angular frameworks, proficiently utilizing various JavaScript libraries to create dynamic and seamless online experiences. My dedication to staying abreast of industry trends ensures that I deliver innovative solutions. With a focus on optimal user interfaces and functionality, I thrive in collaborative environments, bringing creativity and efficiency to web development projects. My expertise lies in crafting engaging digital solutions that align with the evolving landscape of web technologies. Let's embark on a journey of creating remarkable and user-centric online platforms.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top