mariossimou.dev
HomeBlogContact

An Introduction to Micro-Frontends

Published on 7th November 2022

Design PatternsFront-end Development

Introduction

Microservices are all the rage nowadays, and the main reason behind is scalability. While implementing microservices is a whole new level of complexity, companies want to scale and microservices are doing a really good job on that. However, it wouldn't be reasonable to have such a sophisticated design on the backend without thinking and optimising the frontend. As such, the idea of a small, reusable components is also available on the frontend with the name micro-frontends. With that being saids, in this article I will be talking about micro-frontends and discuss some of the core concepts and ideas around it.

Definition

It wouldn't make sense to start talking about micro-frontends without providing a definition about it, so here it is:

Micro-Frontends is an architectural style were independently deliverable applications are composed into a greater whole

While traditionally we have a single monolithic application that controls the UI aspect of our system, micro-frontends suggests to split it into multiple, smaller, bussiness-oriented components, with each one of them to operate independently. When I say operate independently, I mean that the application will live in its own repository, has its own CI, and runs any necessary tests. This also includes the deployment process, which should not be affected from any other deployment that is happening within the organisation.

Pros & Cons

Some of the benefits that we get from this approach are:

  1. Simple decoupled codebases: The application becomes much simplier with much less logic. Developers will be able to understand the logic much quicker as well as to introduce new features with an easier manner.
  2. Independent Deployment: New features will be deployed more frequently and the team won't need to plan a release in conjunction with another team. The pipeline will be less convoluted and getting a green build won't be a nightmare.
  3. Autonomy: Each team will own its own microfrontend, which enables them to move quickly and effectively. However, for this to work well we need to assume that the service-boundaries of each microfrontend are correct and the business functionality doesn't conflict between different teams.  

However, those benefits don't come without a cost. When we split the monolith into multiple micro-frontends, we automatically lose any benefits related to the built-in routing. From now on, we are responsible to route the customer into the right page, and this can happen with a couple ways:

  • If the micro-frontends live within a cluster and any traffic is going through a load balancer, rules can be added to the load balancer and navigate clients to the right paths/domains.
  • The organisation creates an application-container, which essentially is another application that will handle the routing and forward any traffic to the right location. This application will also provide shared styles and components such as header and footer between the micro-frontends. Here is a code snippet that proves my sayings:
<!DOCTYPE html>
<body>
    <div id="root"></div>
    <script>
        const microfrontendsMap = {
            '/': 'http://domainA/index.js',
            '/orders': 'http://domainB/index.js'
        }
        const src = microfrontendsMap[window.location.pathname]

        if(src){
            const script = document.createElement('script')
            script.defer = false
            script.async = true
            script.src = src

            document.head.append(script)
        }

    </script>
</body>
</html>

The application container will try to find a match within then microfrontendsMap of the current path. If so, it will create a script and load the logic related to the microfrontend.

Styling

While in the past styling was a major issue for micro-frontends, this has changed and many technologies have evolved to mitigate the problem of CSS and global scope. Nowadays, technologies such as SCSS/SASS, CSS-modules and CSS-in-JS are preferred since they localise the scope of styles to per component.

Shared Component Libraries

Since we split a monolith into multiple micro-frontends, you may be thinking that each team will be building it's own components, but this is not exactly the case. There are some type of components that don't involve any business-related functionality, and we often want to abstract them to a shared library that will be used by the teams. Components such as Buttons, Inputs, Typography and Fonts fall within that umbrella, allowing us to accomplish a couple of things:

  • Enforce consistensty between our pages
  • Reduce the workload from the teams and give them time to focus building components related to their domain of experty.

However, if you are in an early phase of your development, take the time to observe patterns and identify the components that should be abstracted to a shared library. With that been saids, avoid premature optimisations, which include cases of moving a component that is not mature enough. I would advice to wait until the component becomes stable, and then move forward abstracting it to a shared library. Abstracting an unstable component to shared library can lead to much more issues than you initially anticipated and there is no way back from that point.

Backend Communication

Backend-For-Frontend (BFF) is a common architectural design in microservices and simply says that each microfrontend needs to have it's own backend.

While traditionally teams build a general-purpose API that supports the communication between the UI and the backend services, this becomes extremely complex and it is not clear who owns the service. The obvious solution would be to create a dedicated team that owns it, but we automatically lose any benefits we gained by creating autonomous teams (we want to avoid splitting our business functionality per technology stack, rather than split it per domain). For example, to introduce a new feature, the team that owns one of the micro-frontends and the API team need to coordinate their development and release cycles. The whole point of micro-frontends is to decouple services.

In contrast, allowing each team to have its own backend and assigning ownership to them, they are more flexible to add changes and they gain a broader understanding of how things work.

Moreover, when we talk about user interaction, we often talk about desktop, tablets and mobile devices. Do I create a single BFF for all of them, or create one BFF for each one of them?  

The answer is, depends. It depends on how much logic is shared between the devices. If the views and the business logic deviates significantly, then it makes sense to split it and have a dedicated BFF for each one of them. Otherwise, have a single BFF and when you feel there is a need to split, create another BFF and connect it to the device that it needs.

Summary

Micro-Frontends it's a great way to scale your frontend application, however, as anything in tech, it has it's pros and cons. We have also proposed some options related to styling, as well as discussed the meaning of shared libraries in micro-frontends. Lastly, we talked about backend-for-frontends (BFF), which is a common design pattern used along micro-frontends to support and centralise any communication between the frontend and the backend services.

Sources:

Designed by
mariossimou.dev
All rights reserved © mariossimou.dev 2023