I recently wrote about five reasons why it’s worth adopting a micro frontend architecture. Of course, there are pros and cons to everything. Micro frontends are a fresh architectural approach, and are likely to represent the future of web development. At the same time, they come with a few pitfalls, and knowing them is critical to being able to address or avoid them completely.
In this article, you’ll learn the most important lessons my team and I learned while using micro frontends. Over a two-year period, we identified many issues with this architecture and made just as many mistakes. So, it’s time to share them to help you tackle or avoid them.
Let’s first recall what the micro frontend architecture is, and then dive into their pitfalls and how to avoid each of them.
Micro Frontends in a Nutshell
Martin Fowler defines the micro frontend approach to development as:
an architectural style where independently deliverable frontend applications are composed into a greater whole.
When applied to web development, it implies having many independent small frontend applications being part of the same website or web application. As already mentioned here, my team had used this approach with success. In particular, we had the opportunity to take advantage of all its benefits, such as scalability, technology independence, and maintainability. On the other hand, over the long term, we noticed some serious issues. So, we decided to abandon this architectural approach to move back to a more traditional monolithic architecture.
This means that not only did we learn the good things that come with micro frontends, but also their major drawbacks. Let’s now delve into them and see what we should have done to avoid or address them.
1. Redundant Dependencies
Every micro frontend application is independent of the others by definition. In other words, a micro-frontend architecture involves more than one frontend application that should be able to work also without the others. To allow this, each of them has its own dependencies. So, looking at the whole, you’re losing the benefits of using a package manager. In fact, your entire application will likely consist of many versions of the same libraries, scattered across the micro frontends.
This is undoubtedly a problem, because it makes your web application unnecessarily larger than its monolithic counterpart would be. This falls on the end users, who are forced to download more data. Moreover, this impacts the rendering time and consequently the Google Web Vitals scores, also affecting your website’s SEO.
How to address this
A possible solution involves three steps. First, identify the set of common libraries across all the micro frontends. Second, create a micro frontend containing all the shared libraries. Then, update your micro frontends to make their built package import the required libraries from this shared project.
As described in Martin Fowler’s original blog post from which this idea comes, sharing dependencies between applications presents many obstacles and can’t be considered an easy task to accomplish. So keep that in mind as you try to achieve this goal.
2. Conflicting and Overlapping Styles
Again, technology and team independence is great, but it can also introduce some issues. This is particularly true when dealing with styling. In fact, each micro frontend can’t have its own style from a business point of view. This is because you definitely don’t want your applications to look composed of many patches. Everything should look consistent, both in terms of style, UI, and UX.
Another problem deriving from having multiple frontends being part of the same application is that you can end up with unintentional CSS rule overrides. Undesired overlaps in terms of CSS become common when dealing with micro frontends, and you may find out about them after only deploying your application. The reason is that each team usually works only on its own application, and doesn’t see the whole picture before a deployment.
These issues can negatively affect your brand reputation. Also, the end users will pay the price for these inconsistencies, especially in terms of UI.
How to address this
The only possible solution when it comes to UI and UX is to make sure that each team talks to the other and has the same outcome in mind. Also, adding styled-components in the aforementioned shared micro frontend project could help here. Nevertheless, this would make each micro frontend application depend on that, and it breaks the underlying independence as a consequence. But at least it will prevent your application as a whole from looking heterogeneous.
If you want to avoid CSS overlapping, a solution involves adding an ID to the frontend container
<div>. Then, configure webpack to insert this ID before each CSS rule. Otherwise, you could decide to adopt a CSS methodology such as BEM (Block-Element-Modifier). This encourages you to think of a website as a collection of reusable component blocks, whose class name should be unique within your project. Read introduction to BEM to learn more about how this system works.
3. Poor Performance
Also, keep in mind that when testing your micro frontend isolated from others, you may not notice this. The problems begin when more than one instance of a framework is running at the same time. This is because, if they are run independently, they don’t have to share the resources of the underlying machine as they will have to when deployed.
How to address this
An idea to solve this problem is to strengthen team communication to avoid making the same calls and elaborations. Then, store their result in a place each micro frontend has access to, or allow them to communicate before performing a heavy operation to verify if the same data has already been retrieved or generated before.
Also, when it comes to performance, you must test the application with all its micro frontends, and don’t rely on tests made on each micro frontend alone.
4. Communication between Frontends
Initially, you won’t need to make your micro frontends communicate, except in rare cases. This might fool you into thinking that it will always be this way. Also, though the micro frontend architectural pattern is about independence, this is opposed to communication.
When the application as a whole grows, making your micro frontends able to communicate effortlessly with each other is likely to become a priority. Above all, if you want to keep repeating the same operations over and over, especially if they aren’t idempotent.
Also, communication is necessary to achieve higher performance, as explained above. For example, you don’t want your application to make the same API call twice to retrieve the same data and slow down your server unnecessarily.
How to address this
The solution is to implement a custom messaging layer based on a shared state stored in a cookie or localStorage, or on custom-defined events. As you can imagine, implementing this comes with a cost and can quickly become complex and cumbersome to handle. Also, take into account that communication introduces overhead. So, you have to be sure that what you’re building will bring real benefits, and won’t slow down your application even more.
5. Communication Issues between Teams
Communication in a large team can be a problem, but nothing is worse than communication between several teams. This is because having multiple teams working on different codebases means that finding reusable features, functions, and utilities becomes harder. This is bad in terms of code discoverability and therefore reusability. In other terms, you may easily end up with duplicate implementations of the same components across different micro frontends.
How to address this
The solution is to support a logic of communication between teams from the beginning. As mentioned above, this involves having one project with reusable resources for each technology adopted. But having such a project without keeping it up to date would make it useless.
So, you must allow each team to add components and libraries to it. Also, having a team dedicated to this could make the entire process easier. In fact, it may not be easy for an independent and isolated team to understand which elements will be shared by more than one micro frontend.
Moreover, don’t think of technology independence as several isolated teams. On the contrary, having teams talking to each other and keeping themselves up to date is critical for the success of the project. Thus, fostering a culture of communication must be one of the key elements when adopting a micro frontend architecture.
In this article, we looked at the five biggest pitfalls of the micro frontend architectural approach, backed by the experience my team accumulated while working with it daily for two years. Although the micro frontend approach lets developers divide a frontend application into smaller independent parts, this doesn’t mean that each team should also be isolated. On the contrary, sharing solutions, components, resources, and knowledge is the key to success.
Unfortunately, we didn’t know this as a team. Thus, we were forced to abandon our micro frontend journey. But we learned a lot from this adventure, and I hope it’s been useful to share the main causes that led us to a failure and how to avoid or counteract them.
Thanks for reading! Feel free to reach out to me with any questions, comments, or suggestions.