Contentstack: What is a micro-frontend approach?

We know what a backend is in software terms – it’s all the componentry that go towards bringing our platform and infrastructure layers into being so that we can start to create code-based functionality and move towards the upper frontend.

Logically then, we know what a frontend is – if we (perhaps quite rudimentarily) talk about the frontend as the User Interface (UI) and perhaps also in more developer-centric language we also incorporate any other elements of software that would be defined as falling into the ‘presentation layer’ as it is.

Given that basic exposition, should we also be asking ourselves if we know what a micro-frontend is? Abhinav Paliwal, application engineer at Content Experience Management company Contentstack wants to explain. 

Paliwal writes as follows from this point forwards…

Microservices are backend

Even though microservices have revolutionied and accelerated the way we develop modern apps, they have focused a lot on the back end. By comparison, the front-end of tech stacks have remained pretty monolithic in terms of their architecture.

In the face of this, we took to exploring just what microservices can do for the front end and called the approach a ‘micro-frontend’. What follows is a practical, hands-on guide of what one software team has learnt in the process.

Why micro-frontend: scale

A single, unified, ‘monolithic’ frontend works well whilst your app is catering to only a handful of customers. But as the technology grows and demands for more capabilities increase, the inflexibility of a single, large frontend throttles the pace of your delivery.

We have broken down our application into several sub-domains, with each one being developed and owned by separate teams. When the different codebases from all these teams came together into a single application, there were natural consequences:

  • All the teams had to sync often on deployment and testing.

  • Releases needed to be coordinated across the different teams and their schedules.

  • Merge conflicts occurred frequently.

  • It was not an efficient approach and certainly not scalable…. so dividing the frontend into smaller apps was the need of the hour.

How to micro-frontend

There are several ways to build micro-frontends. After some initial research, we found the following two ways to be more suitable – although there might be better fits for you elsewhere.

Iframes

This approach is defined at https://micro-frontends.org/

We tried the iframes approach initially. It was, however, not an effective approach for us, as it has issues related to security, usability and SEO. However, it helped us bootstrap a repository and get the micro-frontend on the screen to start development.

The second approach, as suggested by micro-frontends.org, leverages custom DOM elements. While the approach is well thought out, we realised that it could be overkill as we don’t use multiple frameworks — we use ReactJS across projects — and we don’t have many use cases for out-of-the-frame rendered components.

Later, we came across the blog: 5 Steps to Turn a Random React Application Into a Micro Front-End. It suggests a few methods to help implement a micro-frontend the way we wanted, and they eventually became the base for our implementation. So let’s look at the method more in detail.

The implementation

The basic implementation includes using a dynamic script tag to load the micro-frontend JavaScript on the page. Once loaded, the container calls a method on the window object. The micro-frontend provides this method to start the rendering process. The micro-frontend renders to a div as exposed by the container. Eventually, you get a setup that looks like the illustration on the right.

The container app renders sections in green, and the section in blue is the micro-frontend.

Rendering challenges & solutions

While the initial success using the above approach was quite encouraging, it was short-lived. We faced a significant challenge and we quickly realised that our implementation needed to be slightly different:

As you can see in the illustration above below right, the micro-frontend also needed to render a few components outside its DOM hierarchy. The left navigation bar and the top header need to render certain buttons, icons, and other components sourced from the micro-frontend.

We realised that we could use the React Portals API to solve this. This API allows you to render components outside the DOM tree where the micro-frontend is rendered. Using some well-known div IDs, we were able to expose an API where the micro-frontend can control these sections in the UI.

Another challenge was to have a seamless routing experience when the micro-frontend wanted to change routes. Managing this became a little easier since we are creating a single-page application (SPA) with HTML 5 pushState API. When initialising the micro-frontend, we could pass the history object, which the micro-frontend can then use. Also, we used relative routes, so it worked without a hitch.

Further challenges & solutions

One unfortunate side effect to having independent micro-frontends is the relative size of each micro-frontend JavaScript bundle. Nowadays, loading an average ReactJS app and all the standard libraries consumes several megabytes of bandwidth. By implementing micro-frontends, we were going to multiply this with the number of micro-frontends in use.

Some of the libraries that we use (such as React, Redux, Redux-Saga) are common among all the micro-frontends we have built. So, it did not make sense to download these common libraries for each micro-frontend. Instead, a better approach would be to bundle them together so you could download them only once.

We achieved this using dll-plugin, a library for Webpack. It allows us to bundle the common libraries into a “DLL” (Dynamically-Linked-Library) that you can dynamically load within a webpack project. By using the DLL plugin, we achieved a significant 60% reduction in our bundle size.

So you still want a micro-frontend?

Our application’s new user interface and some of our new incubation projects now have micro-frontends implemented, based on the approach given above. And all these apps have been working smoothly. We can roll out more changes quickly with less dependency on other teams, so deployment and scaling become more manageable.

If you want the details of this approach, check out our micro-frontend example (with code) on GitHub.