Quick Summary:
This blog covers a complete guide on how one can implement React Micro frontend along with a firm understanding of the React Microservices Architecture, the benefits of such monolithic applications built using React Micro frontend, the various implementations of the same, and an ideal tutorial for building Micro frontend with React.
Monolithic architecture, which has been the norm in software development for decades now, is being replaced by microservices as an alternate strategy. Initially, the success of monolithic designs has a long history. Consequently, several software vendors and industry leaders firmly believe in its benefits. But as times change, new technical advancements appear that are more advantageous than what everyone seems to be accustomed to.
React micro frontend architecture is not a new concept; rather, it is a progression of earlier architectural patterns. Disruptive innovation trends in social media, cloud computing, and the Internet of Things are heavily influencing the platform of microservice architecture to quickly penetrate the market.
Thanks to the move to continuous deployment. Microservices, in the form of React micro frontend help businesses in the following ways:
Let us show you a tutorial guide to building React Micro frontend. Here, we will be building two applications, namely, a host and remote; where the main application is the host, and another one will be a sub-app that we plug into it.
The host app will be our “main” app and the remote app will be a sub-app plugging into it.
First, we will be creating a basic react app using create-react-app.
This will create two apps for you:
1. host-app/
2. remote-app/
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.
Do you wish to create a React Micro Frontend application for your users to hastily find them their solution and to scale your business?
Hire Reactjs developers from Bacancy as we are early adopters of the magnificent possibilities in the frontend. Our veteran React developers have years-long experience with industry-wide domains of small & big dimensions.
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:-
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
// Note: It is important to import bootstrap file dynamically using import() statement otherwise you will see the same error.
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 / > );
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.
We need to use a lazy loader and also an ErrorBoundary component to create a smooth experience for users in case the fetching takes a long time or introduces errors in our host app.
// host-app/src/App.js import React from "react"; import ErrorBoundary from "./ErrorBoundary"; const RemoteApp = React.lazy(() => import("Remote/App")); const RemoteButton = React.lazy(() => import("Remote/Button")); const RemoteWrapper = ({ children }) => ( ); export const App = () => ( ); export default App;{children}
You can add the ErrorBoundary component from this repo.
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"], }, }, }), ], };
Important things to note:
Name:- It is used to distinguish the modules.
Remotes:- It is where we define the federated modules we want to consume in this app. You’ll notice we specify Remote as the internal name so that we can load the components using import(“Remote/
Shared:- It is how we share dependencies between modules. This is very important for React because it has a global state, meaning you should only ever run one instance of React and ReactDOM in any given app. To achieve this in our architecture, we are telling webpack to treat React and ReactDOM as singletons, so the first version loaded from any modules will be used for the entire app. As long as it satisfies the requiredVersion we define. We are also importing all of our other dependencies from package.json and including them here, so we can minimize the number of duplicate dependencies between our modules.
Now, if we run npm start in the host app we will be able to see the output on the screen.
This means our host app is configured, but our remote app is not exposing anything yet. So we need to configure that also.
Let’s start with the webpack configuration file. As we have configured it host-app, we have some knowledge of Module Federation:
Add the following code to the plugins.
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:
exposes is where we define the code we want to share in the moduleEntry.js file. Here we are exposing two files: < App / > and < Button / >.
Now We can set up those components and our Remote app so it can run independently.
import React from "react"; export const App = () => { return Hello from the Remote App; }; export default App;
And we also want to expose a < Button / > component.
Now We have configured the Remote app and if you run npm start we can see a blank page with “Hello from the other side.”
Now you can put both repos in one folder and start both on single command:-
One package.json file will be created. Now add the following changes in package.json:-
"workspaces": { "packages": [ "host", "remote" ] }, "scripts": { "start": "npm run start:host & npm run start:remote", "start:host": "cd ./host-app && npm start", "start:remote": "cd ./remote-app && npm start", "start:all": "yarn workspaces run start", "cleanup": "yarn workspaces run cleanup" },
This will run both repos in a single command. And you can see the output.
The developer doesn’t recommend creating a react micro frontend App using the create-react-app command. However, we hope you found this tutorial helpful.
Typically, some crucial elements have contributed significantly to the popularity and momentum of micro frontend architecture. The bulk of product-based businesses uses the micro frontend architecture to speed up and lower the cost of development. In the upcoming years, monolith design might only be used for developing prototypes of new goods, while micro frontend architectures that offer modularity and simple scaling of programs might be employed for mainstream development.
The core idea behind developing micro frontends is to be technology agnostic, to isolate team code, to establish team prefixes, to favor native browser features over custom APIs, and to build a resilient site.
Some of the evident cons of micro front-end architecture are a lack of control over interfaces between modules, increased payloads, complex development processes, and cohesive UX.
New feature roll outs, performance enhancements, and reusability of code are the pros of having a micro front-end architecture.
Navigating client's requirement with precision is what our developers' focuses on. Besides, we develop to innovate and deliver the best solutions to our clients.
get in touchYour Success Is Guaranteed !
We accelerate the release of digital product and guaranteed their success
We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.