Microfrontends
GatsbyJS’s Founder Kyle Mathews made a profound observation recently, stating that, "Websites today are still made the same way they were 20 years ago, with a cumbersome monolithic approach to building sites, storing data, and delivering content. It’s time for a new way to build the web."
This led me to think our current architectural approach to web development. The need for a new model was apparent - today's projects are becoming increasingly complex, and the bundle size of JavaScript is expanding. This is not only increasing the initial load time whenever a user types a URL but also leading to several other issues.
For instance, some features are effortlessly developed in specific frameworks or libraries, but in others, it becomes a complex task. This calls for an architectural paradigm that is library or framework-agnostic, thus allowing all frameworks and libraries to co-exist harmoniously.
These challenges led to the development of a new architecture inspired by microservices, thus giving birth to the concept of microfrontends.
Looking back through the progression of this evolution:
Initially, we had monorepos where all the mobile, web, and other apps were stored in the same place. Over time, the monolithic architecture was adopted, where the frontend application was stored, managed, and developed independently. The backend team then followed suit with their own backend tasks. Next came the concept of microservices architecture where the backend team was divided into different teams based on feature development. Each team would work in isolation and deploy their code independently. This triggered a desire to achieve a similar architecture on the frontend. As a result, frontend developers started dividing large complex applications into smaller ones, based on the features they provide, and build them individually. This enabled all the teams to better understand and be responsible for the features they were building the UI for. See below to understand that evolution.
So, what is microfrontend? We can define it as the extension of microservices in the world of frontend or the decomposition of a monolithic frontend app into smaller, independently deployable components.
We've now discussed how to segregate microfrontends, but we still need to integrate these different microfrontends into one container or shell. To do this, there are two approaches:
In build-time integration, we develop the app, deploy it, and publish it as an npm package to the npm repository. It's then installed as a dependency in the shell micro frontend and built there. The issue with this approach is that we need to build the shell application again to reflect any deployed microfrontend.
In run-time integration, we deploy each microfrontend at a URL like www.xyz.com/app1. In the shell micro frontend, we can fetch the hosted microfrontends with the help of module federation(webpack) and display it in the shell.
Here's how to implement it:
First, you need to expose the app or component at the microfrontend by placing the component path in the expose attribute in the webpack.config.js file.
领英推荐
plugins: [
new ModuleFederationPlugin({
name: "mfe1",
filename: "remoteEntry.js",
remotes: {},
exposes: {
"./mfe1": "./src/App.jsx",
"./header": "./src/Header.jsx",
}
})
],
In the shell application, we need to add the exposed microfrontend paths in remotes.
plugins: [ new ModuleFederationPlugin({ name: "shell", filename: "remoteEntry.js", remotes: { "mfe1": "mfe1@https://localhost:9001/remoteEntry.js>", "mfe2": "mfe2@https://localhost:9002/remoteEntry.js>" }, exposes: {}, }), ]
Then, we can easily import the microfrontend app or components of microfrontends in the shell application. This is a simple example of how to inject microfrontend 1 and microfrontend 2 into a shell application.
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import MFE1 from "mfe1/mfe1"
import Header from "mfe1/header"
import MFE2 from "mfe2/mfe2"
const App = () => (
<div className="container">
<div>Name: shell</div>
<div>Framework: react</div>
<div>Language: JavaScript</div>
<div>CSS: Empty CSS</div>
<div>
<div>
<Header />
<MFE1 />
</div>
<div>
<MFE2/>
</div>
</div>
</div>
);
export default App;
With the help of module federation, we can now easily integrate microfrontends. To establish communication between the microfrontends, we can use a variety of strategies, such as local storage (though that might seem like a funny suggestion), centralized state management like Redux, custom events, or a custom message bus.
Here is a GitHub repo where I've implemented microfrontends in a simple and easier way. You can clone it and follow the steps mentioned in the readme file to see the microfrontends in action.
The key advantages of using Microfrontends are:
Disadvantages of using Microfrontends:
To wrap things up, microfrontends are definitely a game-changer, in my opinion. They may seem a bit tough to handle at first, but once you get the hang of them, you'll see how they can help make work smoother, faster, and easier across different teams.
Still, just like everything else in web development, microfrontends aren't perfect. They have some tricky parts we need to tackle, like setting up and managing dependencies. But hey, we're no strangers to a good code challenge, right? If we plan it right and understand the ins and outs, we can make the most out of microfrontends for our projects.
So, let's embrace this new way of building web apps, learn more, and push the boundaries of what we can achieve in web development.
Docente, Pesquisador e Desenvolvedor Fullstack | Php, Laravel, C#, .Net, .Net Core, asp.Net, Java, Javascript, NodeJs, Typescript, Nextjs, Reactjs, React Native e Vuejs
2 个月I invite you to participate in this form, which is part of the scientific research for my master's dissertation. Your responses will be essential to the success of this study. You consent to share the information provided by completing and submitting the form. I thank you in advance for your valuable contribution. https://forms.gle/2KXna2KbQp71Jgj39