In modern web development, as applications grow in complexity, it becomes increasingly difficult to maintain a monolithic frontend. To address this, the micro frontend architecture pattern has emerged. Micro frontends break down a large frontend application into smaller, more manageable parts, making it easier for teams to develop, deploy, and scale applications independently.
In this article, we will explain what micro frontends are, why they are useful, and how you can implement them with simple examples, even if you're a beginner.
What are Micro Frontends?
The micro frontend architecture is inspired by microservices in backend development. Instead of building a large, monolithic frontend application, a frontend is split into smaller, loosely coupled modules. Each of these modules is responsible for a specific feature or section of the UI. These modules can be developed, tested, and deployed independently by different teams.
In simpler terms, imagine a website that contains several sections such as a navigation bar, a product list, and a user profile. With micro frontends, each of these sections could be developed and deployed separately by different teams using different technologies. At runtime, these individual pieces of the application come together to form a cohesive user interface.
Why Use Micro Frontends?
Micro frontends offer several benefits, especially for large teams and complex applications:
- Scalability: Each module can be scaled independently, allowing teams to manage resources more efficiently.
- Independent Deployment: Teams can deploy parts of the application without affecting other sections.
- Technology Agnostic: Each module can use different technologies or frameworks (React, Vue, Angular, etc.), allowing flexibility in choosing the best tools for specific tasks.
- Improved Collaboration: Since each team owns a specific module, it improves team autonomy and parallel development.
However, there are also some trade-offs, such as additional complexity in managing different parts of the application, potential performance issues due to multiple frameworks, and the need for coordination between teams.
How Do Micro Frontends Work?
The general idea of micro frontends is to break down a large, complex web application into smaller, self-contained parts that can be developed and deployed independently. Here's how they come together:
- Modular Design: Each micro frontend is a separate module or "slice" of the overall frontend application. Each module encapsulates its own logic, style, and behavior.
-
Integration: These modules are integrated at runtime. The integration could happen at different levels, such as:
- Server-Side Composition: The server assembles the final UI by serving different micro frontends.
- Client-Side Composition: The client (browser) assembles the UI by loading different micro frontends from separate URLs.
- Web Components: Micro frontends can be packaged as web components, which are reusable custom HTML elements.
In this article, we will focus on client-side composition for simplicity, where different micro frontends are loaded dynamically into the same page.
Example: Building a Micro Frontend System
Let's break down the implementation of a simple micro frontend system. We'll build a small e-commerce site where the product list and the shopping cart are handled by separate micro frontends.
We'll use React for simplicity, but remember, you can use any technology stack (Angular, Vue, etc.) for different micro frontends.
Step 1: Set up the Host Application (Container)
The host application is responsible for integrating all the micro frontends. It will load the different micro frontends and render them in the browser.
- Create a new React project for the host application.
npx create-react-app micro-frontend-container
cd micro-frontend-container
-
Install dependencies for loading remote micro frontends. We'll use
webpack
andModule Federation
to load remote modules.
npm install --save @module-federation/webpack
-
Create a
webpack.config.js
file to enable Module Federation for loading the remote micro frontends.
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
devServer: {
port: 3000,
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
},
],
},
};
-
Configure
Module Federation
inwebpack
to load micro frontends:
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
// ... previous configuration
plugins: [
new ModuleFederationPlugin({
name: 'container',
remotes: {
product: 'product@http://localhost:3001/remoteEntry.js',
cart: 'cart@http://localhost:3002/remoteEntry.js',
},
}),
],
};
The container
will load two remote micro frontends: product
(from a server running at http://localhost:3001
) and cart
(from a server running at http://localhost:3002
).
Step 2: Create the Product Micro Frontend
Now, let's build the Product Micro Frontend.
- Create a new React app for the product micro frontend.
npx create-react-app product
cd product
-
Set up the Module Federation in
webpack.config.js
for the product micro frontend.
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
mode: 'development',
devServer: {
port: 3001,
},
plugins: [
new ModuleFederationPlugin({
name: 'product',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/ProductList',
},
}),
],
};
-
Create a simple
ProductList
component:
// src/ProductList.js
import React from 'react';
const ProductList = () => {
return (
<div>
<h2>Product List</h2>
<ul>
<li>Product 1</li>
<li>Product 2</li>
<li>Product 3</li>
</ul>
</div>
);
};
export default ProductList;
- Start the product server:
npm start
Now, the product micro frontend will be available at http://localhost:3001/remoteEntry.js
.
Step 3: Create the Cart Micro Frontend
Next, we build the Cart Micro Frontend.
- Create a new React app for the cart micro frontend.
npx create-react-app cart
cd cart
-
Set up Module Federation in
webpack.config.js
for the cart micro frontend.
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
mode: 'development',
devServer: {
port: 3002,
},
plugins: [
new ModuleFederationPlugin({
name: 'cart',
filename: 'remoteEntry.js',
exposes: {
'./Cart': './src/Cart',
},
}),
],
};
-
Create a simple
Cart
component:
// src/Cart.js
import React from 'react';
const Cart = () => {
return (
<div>
<h2>Shopping Cart</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
);
};
export default Cart;
- Start the cart server:
npm start
Now, the cart micro frontend will be available at http://localhost:3002/remoteEntry.js
.
Step 4: Load the Micro Frontends in the Host Application
Now, let's update the Host Application to load the ProductList
and Cart
components from the remote servers.
-
Update
App.js
in the host application:
// src/App.js
import React, { Suspense } from 'react';
// Dynamically import remote components
const ProductList = React.lazy(() => import('product/ProductList'));
const Cart = React.lazy(() => import('cart/Cart'));
function App() {
return (
<div className="App">
<h1>Micro Frontend Demo</h1>
<Suspense fallback={<div>Loading...</div>}>
<ProductList />
<Cart />
</Suspense>
</div>
);
}
export default App;
In this code, we use React's Suspense
to load the remote ProductList
and Cart
components.
Conclusion
Congratulations! You have now implemented a basic micro frontend system using React and Webpack's Module Federation. Here's a recap of what we've done:
- We created a host application that loads two remote micro frontends (
Product
andCart
). - We built two independent micro frontends and set up Webpack's Module Federation to enable communication between the host and the remote modules.
- Finally, we integrated the micro frontends in the host application using React's
Suspense
for lazy loading.
This is just the beginning. As you dive deeper into micro frontends, you'll encounter more complex use cases, such as handling shared state, styling, and managing deployment across different environments.
But with this foundational knowledge, you're now well-equipped to start building scalable, modular frontends with micro frontends!
Top comments (0)