Explore integration strategies for micro frontends, including server-side composition, client-side composition, Edge-Side Includes, Module Federation, Web Components, and more.
Micro frontends are an architectural style where the frontend monolith is decomposed into smaller, more manageable pieces, each owned by different teams. This approach allows for greater flexibility, scalability, and independence in frontend development. However, integrating these micro frontends into a cohesive application presents unique challenges. In this section, we will explore various integration strategies that can be employed to effectively manage and orchestrate micro frontends.
Server-side composition is a strategy where the backend server is responsible for assembling and serving the final HTML page by aggregating micro frontends. This approach offers several advantages, particularly in terms of SEO and initial load performance.
Consider a scenario where a news website is composed of multiple micro frontends, each responsible for different sections like headlines, sports, and weather. The server-side composition can be implemented as follows:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class ServerSideComposer {
public static void main(String[] args) {
try {
String headlinesHtml = fetchHtml("http://microfrontend-headlines.com");
String sportsHtml = fetchHtml("http://microfrontend-sports.com");
String weatherHtml = fetchHtml("http://microfrontend-weather.com");
String finalPage = "<html><body>"
+ headlinesHtml
+ sportsHtml
+ weatherHtml
+ "</body></html>";
System.out.println(finalPage);
} catch (IOException e) {
e.printStackTrace();
}
}
private static String fetchHtml(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
Scanner scanner = new Scanner(url.openStream());
StringBuilder html = new StringBuilder();
while (scanner.hasNext()) {
html.append(scanner.nextLine());
}
scanner.close();
return html.toString();
}
}
In this example, the server fetches HTML content from different micro frontends and assembles them into a single HTML page.
Client-side composition involves loading and integrating micro frontends dynamically within the browser. This strategy provides greater flexibility and independence for frontend teams, as each micro frontend can be developed and deployed independently.
Using JavaScript, client-side composition can be achieved by dynamically loading micro frontends:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Client-Side Composition</title>
</head>
<body>
<div id="app"></div>
<script>
function loadMicroFrontend(url, containerId) {
fetch(url)
.then(response => response.text())
.then(html => {
document.getElementById(containerId).innerHTML = html;
})
.catch(error => console.error('Error loading micro frontend:', error));
}
loadMicroFrontend('http://microfrontend-headlines.com', 'app');
loadMicroFrontend('http://microfrontend-sports.com', 'app');
loadMicroFrontend('http://microfrontend-weather.com', 'app');
</script>
</body>
</html>
This approach allows the browser to fetch and render micro frontends dynamically, providing a seamless user experience.
Edge-Side Includes (ESI) is a templating language that allows for the dynamic assembly of web pages by including snippets from different micro frontends at the edge servers. This strategy leverages Content Delivery Networks (CDNs) to improve performance and scalability.
An ESI template might look like this:
<html>
<body>
<esi:include src="http://microfrontend-headlines.com" />
<esi:include src="http://microfrontend-sports.com" />
<esi:include src="http://microfrontend-weather.com" />
</body>
</html>
The edge server processes these ESI tags, fetching and assembling the content before delivering it to the client.
Webpack 5’s Module Federation feature enables the sharing and loading of modules between different micro frontends, facilitating efficient and dynamic integration without monolithic bundling.
In a Webpack configuration, Module Federation can be set up as follows:
// webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "app",
remotes: {
headlines: "headlines@http://localhost:3001/remoteEntry.js",
sports: "sports@http://localhost:3002/remoteEntry.js",
},
shared: ["react", "react-dom"],
}),
],
};
This configuration allows the app
to consume modules from the headlines
and sports
micro frontends.
Web Components provide a standard for building encapsulated, reusable frontend elements that can be integrated seamlessly across micro frontends, ensuring interoperability and consistency.
A simple Web Component can be created using the following JavaScript:
class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `<p>Hello, I'm a Web Component!</p>`;
}
}
customElements.define('my-component', MyComponent);
This component can be used in any HTML page as <my-component></my-component>
.
Single-SPA is a framework for orchestrating multiple micro frontends within a single application, managing lifecycles, routing, and inter-module communication.
A basic Single-SPA setup might look like this:
import { registerApplication, start } from "single-spa";
registerApplication({
name: "@org/microfrontend",
app: () => System.import("@org/microfrontend"),
activeWhen: ["/path"],
});
start();
This setup registers a micro frontend to be active when the URL matches /path
.
Consistent state management across micro frontends is crucial for synchronizing data and user interactions. Shared state containers or global state management solutions can be employed to achieve this.
Optimizing the performance and load times of integrated micro frontends is essential for ensuring a smooth and responsive user experience.
Integrating micro frontends requires careful consideration of various strategies to ensure a cohesive and performant application. By leveraging server-side and client-side composition, Edge-Side Includes, Module Federation, Web Components, and frameworks like Single-SPA, developers can create scalable and maintainable frontend architectures. Consistent state management and performance optimization further enhance the user experience, making micro frontends a powerful approach for modern web applications.