What is Micro-frontend?
An architectural style where independently deliverable frontend applications are composed into a greater whole
Benefits
- Smaller, more cohesive and maintainable codebases
- More scalable organisations with decoupled, autonomous teams
- The ability to upgrade, update, or even rewrite parts of the frontend in a more incremental fashion than was previously possible
- Easier maintenance: Keeping frontend repositories small and specialized allows them to be more easily understood, and this simplifies long-term maintenance and testing.
Micro-Frontend in actions
Build-time integration
- Publish each micro frontend as a package and have the container application include them all as library dependencies.
{
"name": "@shop/container",
"version": "1.0.0",
"description": "E-commercial website",
"dependencies": {
"@shop/products": "^1.0.0",
"@shop/order": "^1.0.0",
"@shop/user-profile": "^1.0.0"
}
}
Cons
- Have to re-compile and release every single micro frontend in order to release a change to any individual part of the product.
Run-time integration via iframes
- Use iframe to connect other micro frontends.
<html>
<head>
<title>Shop</title>
</head>
<body>
<h1>Welcome to Shop</h1>
<iframe id="app-container"></iframe>
<script type="text/javascript">
const microFrontendsByRoute = {
"/": "https://products.shop.com/index.html",
"/order": "https://order.shop.com/index.html",
"/user-profile": "https://profile.shop.com/index.html",
};
const iframe = document.getElementById("app-container");
iframe.src = microFrontendsByRoute[window.location.pathname];
</script>
</body>
</html>
Cons
- Difficult to make page responsive
- Difficult to integrate between different parts of application, make routing, history, and deep-linking more complicated
Run-time integration via JavaScript
- Each micro frontend is included onto the page using a
<script>
tag, and upon load exposes a global function as its entry-point. The container application then determines which micro frontend should be mounted, and calls the relevant function to tell a micro frontend when and where to render itself.
<html>
<head>
<title>Shop</title>
</head>
<body>
<h1>Welcome to Shop</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they attach entry-point functions to `window` -->
<script src="https://products.shop.com/bundle.js"></script>
<script src="https://order.shop.com/bundle.js"></script>
<script src="https://profile.shop.com/bundle.js"></script>
<div id="app"></div>
<script type="text/javascript">
// These global functions are attached to window by the above scripts
const microFrontendsByRoute = {
"/": window.renderProducts,
"/order": window.renderOrder,
"/user-profile": window.renderUserProfile,
};
const renderFunction = microFrontendsByRoute[window.location.pathname];
// Having determined the entry-point function, we now call it,
// giving it the ID of the element where it should render itself
renderFunction("app");
</script>
</body>
</html>
Run-time integration via Web Components
- Define each micro frontend as an HTML custom element for the container to instantiate.
<html>
<head>
<title>Shop</title>
</head>
<body>
<h1>Welcome to Shop</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they each define a custom element type -->
<script src="https://products.shop.com/bundle.js"></script>
<script src="https://order.shop.com/bundle.js"></script>
<script src="https://profile.shop.com/bundle.js"></script>
<div id="app"></div>
<script type="text/javascript">
// These element types are defined by the above scripts
const webComponentsByRoute = {
"/": "micro-frontend-products",
"/order": "micro-frontend-order",
"/user-profile": "micro-frontend-user-profile",
};
const webComponentType = webComponentsByRoute[window.location.pathname];
// Having determined the right web component custom element type,
// we now create an instance of it and attach it to the document
const root = document.getElementById("app");
const webComponent = document.createElement(webComponentType);
root.appendChild(webComponent);
</script>
</body>
</html>
Cons
- Don't support server-side rendering
- No 100% browser support
Cross-application communication
- Custom event
- Cross-application communication via routing
Serverside rendering / universal rendering
- Server-side rendering is always tricky problem.
- Use Server Side Includes to plug in page-specific content from fragment HTML files:
Cons of micro-frontend
- Duplication of dependencies => increase payload size
- App performance
- Learning curve
- Only suitable for medium, large projects