5 Patterns for Microfrontends

Five Ways To Build Microfrontends in 2024 — The Web Approach, Server-Side Composition, Client-Side Composition, Client-Side Rendering, Build-Time Integration

Lakindu Hewawasam
Bits and Pieces

--

Microfrontends have been around for quite some time. It gained its popularity by being the go-to solution for scaling large-scale web applications.

Different teams started adopting microfrontends and have offered various implementations throughout the years. Therefore, this article will look at different ways that you can build apps using microfrontends.

Pattern 01: The Web Approach

This is one of the simplest approaches to building micro frontends. All you have to do is build a set of web pages, deploy them independently, and make them accessible in a single app by linking them together.

So, with this approach the user goes from website to website by using the links leading to the different servers providing the content.

But, this makes you wonder. If each time builds their own page, how can you keep things consistent?

You can leverage tools like Bit to build a highly maintainable and scalable pattern library.

For example, check out this pattern library that’s available freely on Bit:

Teams can leverage this pattern library across each microfrontend to keep things consistent.

And, to make things better, implementing this approach is as simple as deploying static sites to a server. This could be done with a Docker image as follows:

FROM nginx:stable
COPY ./dist/ /var/www
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx -g 'daemon off;'"]

Now this approach has its set of benefits and drawbacks.

Some of its benefits include:

  1. This is the simplest way to build a microfrontend. It’s less time-consuming making it faster to get started with
  2. It possesses a really low learning curve so teams can quickly adopt this approach.
  3. Your pages are completely isolated from each other as they are deployed independently on different servers.

But, one of the biggest drawbacks to this approach is the fact that it increases your overall infrastructure overheard. This means that you have to put more effort into managing all of the servers.

Pattern 02: Build-Time Integration

Finally, this is where things get interesting. You can build microfrontends that integrate with each other at build time. With this approach, you build in independent environments, but during build time, everything is pieced together into a single app.

For instance, if you’re working with tools like Bit you can build independent React, Vue.js, Angular components and integrate them together at build time to create one single app that’s serving your content.

Bit offers support for you to integrate Vue components onto a React environment during build time.

This brings a lot of benefits:

  1. You have a shorter learning curve as your team does not need to learn a framework they aren’t comfortable with.
  2. You work in an independent environment. Tools like Ripple CI help propagate changes across your component tree automatically.

But, one key drawback with this approach is that you lose design consistency as the design libraries you use on one framework might not offer the same level of support.

Pattern 03: Server-Side Composition

After starting off with the web approach, changes were made to this approach and a more “server-side” approach to a microfrontend was created. With this approach, you no longer link two pages via a link, but rather return composed views from different servers in respect to UI interactions.

Now, the only area of complexity with this approach is its reverse proxy layer. You’ll have to consider things like caching rules and tracking. You can implement this approach with a simple proxy definition as shown below:

http {
server {
listen 80;
server_name www.example.com;
location /api/ {
proxy_pass http://api-svc:8000/api;
}
location /web/admin {
proxy_pass http://admin-svc:8080/web/admin;
}
location /web/notifications {
proxy_pass http://public-svc:8080/web/notifications;
}
location / {
proxy_pass /;
}
}
}

Now, since these sites are served on the server, you no longer have the capability of working with pattern libraries. Therefore, your UI could start to get inconsistent at some point in time, while also adding complexity to maintaining your app.

However, despite these two drawbacks, it still offers a good sense of isolation between your pages allowing you to keep working in a microfrontend nature. Additionally, when comparing with the web approach, the server-side approach makes your site look embedded (all pages in a single monolith), which could improve your overall app user experience.

Pattern 04: Client-Side Composition

But now, you might be wondering — “Do we really need a reverse proxy?” “Doesn’t that add complexity?”

Well, you’re right. You really don’t need a reverse proxy. You can simply use the “client-side composition” approach to build your microfrontends. In it’s simplest form, all you’d need is an iframe element, while you communicate between your microfrontends using the [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) method.

Note: The JavaScript part may be replaced with “browser” in case of an <iframe>. In this case the potential interactivity is certainly different.

Your implementation would look something like the following:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Microfrontend</title>
</head>
<body>
<h1>Child</h1>
<p><button id="message_button">Send message to parent</button></p>
<div id="results"></div>

<script>
const results = document.querySelector("#results");
const messageButton = document.querySelector("#message_button");

function sendMessage(msg) {
window.parent.postMessage(msg, "*");
}

window.addEventListener("message", function(e) {
results.innerHTML = e.data;
});
messageButton.addEventListener("click", function(e) {
sendMessage(Math.random().toString());
});
</script>
</body>
</html>

Using “Client-Side Composition” has its share of benefits and drawbacks.

Some of its benefits include:

  1. This lets you preload, load and render parts of your application on demand, rather than at once, thus, letting you improve the performance of your app.
  2. Your microfrontends are completely isolated from each other.

However, one of its biggest drawbacks is that you might need a JavaScript environment for this to work. You’ll need to use the postMessage API offered in the Window. To do so, you'll need to execute a script in your browser, and thus, might need support to JavaScript for this approach to work.

Although, you can use this approach without any JavaScript as long as your frames don’t communicate with each other.

Modern apps mostly use tools like Module Federaation for better control over mounting, rendering and resource sharing or MFEs. To learn how to implement a Module Federation solution with Bit, read this blog:

Pattern 05: Client-Side Rendering

While client-side composition requires JavaScript for it to work without JavaScript, client-side rendering will fail without JavaScript.

For Client-Side Rendering, you’ll need a framework in the composing application. This framework has to be used by all microfrontends brought in for them to be mounted properly.

You might wonder, isn’t this quite close to the client-side composition?

Well, you’re right. The JavaScript part may not be replaced. However, the biggest difference is that server-side rendering is off the table. Instead, pieces of data are exchanged, which are then transformed into a view.

Depending on the framework the pieces of data may determine the location, point in time, and interactivity of the rendered fragment. Achieving a high degree of interactivity is no problem with this pattern.

With this approach, you get a lot of benefits:

  1. It reduces coupling between your components
  2. It gives a feeling of completeness of the system to the user.

But, one of its biggest issues is that it requires JavaScript. Without JavaScript, this will fail.

Wrapping Up

All in all, this article should give you a basic understanding on the different ways to create microfrontends.

Ranging from simple web integration to server-side composition to build-time integration, you should now know the right technique to use for your next big project!

If you feel like I’ve missed something, let me know in the replies!

Thank you for reading.

Learn More

--

--