Building Micro-Frontends

Scaling Teams and Projects Empowering Developers

With Early Release ebooks, you get books in their earliest form — the author’s raw and unedited content as they write — so you can take advantage of these technologies long before the official release of these titles.

Luca Mezzalira

Building Micro-Frontends

by Luca Mezzalira

Copyright © 2020. All rights reserved.

Printed in the United States of America.

Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.

O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com.

- Acquisitions Editor: Jennifer Pollock

- Development Editor: Angela Rufino

- Production Editor: Christopher Faucher

- Interior Designer: David Futato

- Cover Designer: Karen Montgomery

- Illustrator: Rebecca Demarest

- October 2020: First Edition

Revision History for the Early Release

- 2020-02-20: First Release

- 2020-06-10: Second Release

See http://oreilly.com/catalog/errata.csp?isbn=9781492082996 for release details.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Building Micro-Frontends, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc.

The views expressed in this work are those of the author, and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.

978-1-492-08292-7

Preface

At the beginning of December 2016, I was taking my first trip to Tokyo.
It should have lasted just a week, but as I would discover, I would need to travel to the Japanese capital many more times in the following weeks.

I clearly remember walking to the airplane and mentally preparing my to-do list for the impending 12-hour flight. By now I’d been travelling for a couple of weeks, on the opposite side of the world: attending a couple of conferences in the Bay area and then another event in Las Vegas.

The project I was working at that time was an over-the-top platform similar to Netflix, but dedicated to sports, with daily live and on-demand content available in multiple countries and on more than 30 different devices (web, mobile, consoles, set-top-boxes and smartTVs).

It was near the end of the year, and as a Software Architect I had to make a proposal for a new architecture that would allow the company to scale to hundreds of developers distributed in different locations, without reducing the current throughput and enhancing it as much as I could.

When I was setted in my seat, I became relatively calm. I was still tired from the Vegas trip, and a bit annoyed at the 12 hours I would have to spend on the airplane, but excited to see a mystical country like Japan for the first time.
A few minutes later I had my first glass of Champagne. For the first time in my life, I was in business class, with a very comfortable seat and a lots of space for working.
Definitely the best place to start such a long journey.

At the end of the first hour, it was time to get my laptop out of my backpack and start working on “the big plan”, I still had more than 10 hours of flight time during which I could start working on this huge project that would serve millions of customers around the world. I didn’t know at that time that the following hours would deeply change the way I would architect cross-platform applications for frontend.

In this book I want to share my journey into the Micro-Frontends world, all the lessons and tips for getting a solid Micro-Frontends architecture up and running, finally the PROs and CONs of this approach.
These lessons will allow you to evaluate if this architecture would fit your current or next project.
So now it’s time for your journey to begin.

The Frontend Landscape

I remember a time when web applications were called RIAs or Rich Internet Applications, to differentiate them from the traditional, and more static, corporate websites. Nowadays we can find many “RIAs”, or simply web applications, across the World Wide Web.

Now, many SaaS (Software as a Service) with more or less complex UIs allow us to print our business cards on demand, watch our favorite movies or live events, order a few pepperoni pizzas for us and our guests, manage our bank accounts from our comfortable sofas, and do many, many other things that make our life easier on a daily basis.

As CTOs, architects, tech leads, or simply developers, when we start a greenfield project, we can create a single-page application or an isomorphic one (also called a universal application), or instead work with a bunch of static pages that run in our cloud or on-premise infrastructure.

Yet despite this broad range of opportunities in front of us, not all of them are fitting for any project.
Instead, we need to understand first what challenges we are going to face before taking a direction.

But before jumping straight to the topic of this book, let’s analyze the current architectures available to us when we work on a frontend application.

Single-Page Applications

Single-page applications (or SPAs) are probably the most used implementations by many companies. They consist of a single or a small number of JavaScript files that encapsulate the entire frontend application usually downloaded up front.

When the web servers or the Content Delivery Network (CDN) serve the HTML index page, the SPA loads the JavaScript, CSS, and any additional files needed for displaying any part of our application.

There are many benefits of using SPAs; for instance, the client downloads the application code once at the beginning of its life cycle and the entire logic is available up front.
Also SPAs usually communicate with APIs for exchanging data with the persistent layer of the backend.

An SPA avoids multiple round trips to the server for loading additional application logic and renders all the views instantaneously during the application life cycle.
Both features enhance the user experience and simulate what we usually have when we interact with a native application for mobile devices or desktop, where we can jump from one part of our application to another without waiting too long.

In addition, an SPA fully manages the routing mechanism on the client side.
Usually every time the application changes a view, it rewrites the URL in a meaningful way to allow users to share the page link or bookmark the URL for starting the navigation from a specific page. SPAs also allow us to decide how we are going to split the application logic between server and client. We can have a “fat client” and a “thin server” where the logic is mainly stored on the client side and the server side is used as persistence layer, or a “thin client” and a “fat server” where the logic is mainly delegated to the backend, and the client doesn’t perform any smart logic but just reacts to the state provided by the APIs.

Over the past of several decades, different school of thoughts have prevailed on whatever far or thin clients are better solutions.
Despite these arguments altough, both approaches have their own PROs and CONs. It always depends on the type of application we are creating.
I personally found it very valuable to have a thin client and a fat server when I was targeting cross-platform applications, so I was able to design a feature once and have all clients deployed on multiple targets react to the application state stored on the server.
At the same time, I often used a fat client and a thin server when I had to create desktop applications where the offline persistence layer was an essential feature; therefore, rather than writing the state logic twice, I managed it only in one place and used the server for data synchronization.

However, SPAs have some disadvantages for a certain type of applications. Technically speaking, the first time to load usually takes longer than for other architectures, because we are downloading the entire application instead of only what the user needs to see
If not well designed, this could become a killer for our applications, especially, when they are loaded with an unstable or unreliable connection on mobile devices like smartphones and tablets.

Nowadays there are several ways to mitigate this problem caching the content directly on the client. In particular Progressive Web Apps are providing a set of new techniques, based on service workers, a script that your browser runs in the background, separate from a web page, for enhancing the user experience of an SPA serves on mobile devices with flaky or totally absent connections. Another potential issue caused by SPAs is that are not SEO-friendly; in fact, when a crawler is trying to understand how to navigate the application or website, it won’t have an easy job indexing all the contents served by an SPA unless we prepare alternative ways for fetching it.

Usually when we want to provide better indexing for an SPA, we tend to create a custom experience strictly for the crawler.
For instance, Netflix lowers its geo-fencing mechanism when the user-agent requesting their web application is identified as a crawler, instead serving content similar to what a user would watch based on the country specified in the URL. This is a very handy mechanism considering that the crawlers engine is often based in a single location from which it indexes a website all over the world.
As mentioned earlier, SPAs download all the application logic in one go, but this also can lead to potential memory leaks when the user is jumping from one view to another if the code is not well implemented and is not correctly disposing of the unused objects.

In large applications this could be a real problem that might lead to several days or weeks of application hardening in order to make the SPA code functional.
It could be even worse if the device that loads the SPA doesn’t have a great hardware, like a smart TV or a set-top-box.
Too often I have seen applications running smoothly on a MacBook Pro quad-core and then failing miserably when run on a low end device.

The last disadvantage to mention when we work with SPAs is on the organizational side.
When an SPA is a large application managed by distributed or colocated teams working on the same codebase, different areas of the same application could end up with a mix of approaches and decisions that could confuse team members.
Also the communication overhead teams will use to coordinate between themselves is often a hidden cost of the application.

Many times we completely forget about calculating the inefficiency of our teams, not because they are not capable of developing an application, but because the company structure or architecture doesn’t enable them to express in the best way possible, slowing down the operations and the implementation of any new feature.

Isomorphic Applications

Isomorphic applications, or universal applications, are web applications where the code between server and client is shared and can run in both contexts.

This technique brings some benefits when used in the right way. It is in particular is convenient when the time to interaction, A/B testing, and SEO are essential characteristics for the application.

Isomorphic applications can be designed in different ways.
Because these web applications share code between server and client, the server, for instance, can do the rendering part for the page requested by the browser, retrieve the data to display from the database or from one or multiple APIs, aggregate it together, and then pre-render it with the template system used for generating the view, in order to serve to the client a page that doesn’t need additional round trips for requesting data to display.

This will definitely enhance the time to interaction, considering the page requested is pre-rendered on the server and is partially or fully interpreted on the backend. This spares a lot of roundtrips on the frontend, so we won’t need to load additional resources (vendors, application code, etc.) and the browser will interpret a static page with almost everything inside.

Also, as mentioned, using isomorphic applications can improve an SEO strategy, because the page is server-side rendered without the need for additional server requests when served.
The crawler is going to request the page and receives it fully prepared on the server, ready to be indexed by the search engine without any problem. Isomorphic applications share the code between contexts, but how much code is really shared? To answer this question depends on the context.

For instance, we can use this technique in a hybrid approach where we server-side render part of the page in order to benefit from the time to interact and then lazy loading additional JavaScript files for having the benefits of the isomorphic application as well as the single page application where the files loaded within the HTML page served allow to add sophisticated behaviours to a static web page, transforming this page in a SPA. We can also have a more purist approach where we always render the page and its state on the server providing only a page to display for the browser, really depends on the complexity of the project we are facing.

With this approach, we can decide how much code is shared on the backend based on the project’s requirements.
For instance, we can render just the views, inlining the CSS and the bare minimum JavaScript code to have an HTML skeleton that is loaded very quicly by the browser, or completely delegate the rendering and data integration onto the server, pheraps because we have more static pages than heavy interactivity on the client side. We can also have a mixed approach where we divide the application into multiple SPAs with the first view rendered on the server side, and then some additional JavaScript to download for managing the application behaviors, the models and also the routing inside the SPA.

Routing is another interesting part of an isomorphic application because we can decide to manage it on the server-side, only serving a static page every time the user is interacting with a link on the client.
Or we can have a mixed approach if we use the benefits of server side rendering only for the first view, then load an SPA, where in this case the server will do a macro routing that serves different SPAs, each SPA has its own routing system for navigating between views. Another benefit of this approach is that we are not limited only to template libraries, but virtual DOM implementations like React, Preact, or similar, also can benefit from this approach. Many other libraries and frameworks have started to offer the server-side rendering approach out of the box like Vue with Nuxt.js, Meteor, or Angular, for instance. Also, we don’t need to have a Node.js backend for working with isomorphic apps but we can use the technology we are more familiar with for serving our APIs like Go or PHP for instance.
Isomorphic applications therefore won’t have much of an impact on your existing backend technology stack.

The last thing to mention about isomorphic applications is that we can integrate A/B testing platforms nicely without much effort. In the past year or so, many A/B testing platforms had to catch up with the frontend technologies in not only supporting UI libraries like JQuery but also in embracing virtual DOM libraries like React or Vue. They also have to make their platforms ready for hybrid mobile applications as well as native ones.

The strategy these companies adopted is to manage the experiments on the server side where the developers have full control of the experiments to run on the clients. This is obviously a great advantage if you are working with an isomorphic application because you can pre-render on the server the specific experiment you want to serve to a specific user. Those solutions can also communicate with the clients via APIs in the case of native mobile applications and SPAs for choosing the right experiment.

Isomorphic applications could also suffer from scalability problems if a project is really successful and visited by millions of users. Considering we are generating the HTML page pre-rendered on the server, it means we need to create the right caching strategy in order to minimize the impact on the servers.
In this case, if the responses are highly cacheable, CDNs like Akamai, Fastly, or Cloudfront could definitely improve the scalability of our isomorphic applications by avoiding all the requests hitting origin servers.

Organisation wise, an isomorphic application suffers of similar problems we can find on an SPA where the code base is unique and maintained by one or multiple teams.

There are ways to mitigate the communication overhead if a team is working on a specific area of the application without any overlap with other teams. In this case we can use architecture like Backend for Frontends (BFF) for decoupling the API implementation and allow each team to maintain their own layer of APIs specific to a target.

Static-Page Websites

Before entering the main topic of this book, it is worth mentioning the static-page website, where every time the user clicks on a link we are loading a new static page.
Fairly “old school”, I know, but still in use with some twists.

Usually this approach is useful for quick websites that are not meant to be online for a long period of time, such as ones where freelancers can promote their skills or simply for advertising a specific product or service we want to highlight without using the corporate website.

In the last few years this type of websites has mutated into a single page that expands vertically instead of loading different pages. Another trend in this last case is to lazy-load the content of the website, waiting till the user scrolls to a specific position of the website and then loading the content.

The same technique is used with hyperlinks, where all the links are anchors inside the same page and the user is browsing quickly between bits of information available on the website. These kinds of projects are usually created by small teams or individual contributors; the investment for the company is fairly low on the technical side, and it’s a good playground for developers to experiment with new technologies and new practices or to consolidate existing ones.

Micro-Frontends

Micro-Frontends are an emerging architecture, clearly inspired by microservices architecture.
The main idea behind them is to break down “the monolith” into smaller parts, allowing an organisation to spread the amount of work with autonomous teams, colocated or distributed, without the need to slowing down their delivery throughput.

As we know, encapsulating an API inside a microservice is actually the easiest part.
When we realize there is way more to take care of, we will understand the complexity of the microservices architecture that not only adds high flexibility and good encapsulation between domains, but also an overall complexity around the observability, automation, and discoverability of a system.

Micro-Frontends probably are not suitable for all projects; nevertheless, they can alert us to a new way to structure our frontend applications, solving some of the key challenges we have encountered in the past not only from a technical perspective but also from an organizational one.

Too often I have seen great architectures on paper that didn’t translate well in the real world because the creator didn’t take into account the environment (company’s structure, culture, developers skills, timeline, etc.) where the project should have been built.
As Conway’s law, mentioned in many books, claims:

“Any organization that designs a system (defined more broadly here than just information systems) will inevitably produce a design whose structure is a copy of the organization’s communication structure.”

The Conway’s law could be mitigated with the “Inverse Conway Maneuver,” which recommends that teams and organizations be structured on our desired architecture and not vice versa.

I truly believe that mastering different architectures and investing time on understanding how many systems work allows us to mitigate the impact of Conway’s law, because it gives us enough tools in our belt to solve different challenges, not only technical ones but organizational too.

Micro-Frontends in combination with microservices and a strong engineering culture, where everyone is responsible for their own domain and the final result as well, could result in a real silver bullet - complex to build but foolproof when used.

Conventions Used in This Book

The following typographical conventions are used in this book:

Italic

Indicates new terms, URLs, email addresses, filenames, and file extensions.

Constant width

Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.

Constant width bold

Shows commands or other text that should be typed literally by the user.

Constant width italic

Shows text that should be replaced with user-supplied values or by values determined by context.

Tip

This element signifies a tip or suggestion.

Note

This element signifies a general note.

Warning

This element indicates a warning or caution.

Using Code Examples

This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.

We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Book Title by Some Author (O’Reilly). Copyright 2012 Some Copyright Holder, 978-0-596-xxxx-x.”

If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com.

O’Reilly Online Learning

Note

For almost 40 years, O’Reilly Media has provided technology and business training, knowledge, and insight to help companies succeed.

Our unique network of experts and innovators share their knowledge and expertise through books, articles, conferences, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, please visit http://oreilly.com.

How to Contact Us

Please address comments and questions concerning this book to the publisher:

- O’Reilly Media, Inc.

- 1005 Gravenstein Highway North

- Sebastopol, CA 95472

- 800-998-9938 (in the United States or Canada)

- 707-829-0515 (international or local)

- 707-829-0104 (fax)

To comment or ask technical questions about this book, send email to bookquestions@oreilly.com.

For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com.

Find us on Facebook: http://facebook.com/oreilly

Follow us on Twitter: http://twitter.com/oreillymedia

Watch us on YouTube: http://www.youtube.com/oreillymedia

Acknowledgments

First of all, I’d like to thank my family, my girlfriend Maela, and my daughter Emma for everything we share and the strength I receive from them to move forward every single day. Thanks to all the people who inspire me on a daily basis in any shape or form of communication.

A huge thank to DAZN, who allowed me to apply a Micro-Frontends architecture and to explore the benefits of it end to end trusting my ideas and judgement.
I also thank all my incredible colleagues who challenged and helped me on delivering our platform on more than 30 different targets. Last but not least, thanks to O’Reilly for the opportunity to write about Micro-Frontends, in particular to Jennifer Pollock and Angela Rufino for all the support I had during this journey.

Chapter 1. The Frontend Landscape

A note for Early Release readers

With Early Release ebooks, you get books in their earliest form — the author’s raw and unedited content as they write — so you can take advantage of these technologies long before the official release of these titles.

This will be the 1st chapter of the final book. Please note that the GitHub repo will be made active later on.

If you have comments about how we might improve the content and/or examples in this book, or if you notice missing material within this chapter, please reach out to the author at building.microfrontends@gmail.com.

I remember a time when web applications were called rich internet applications (RIAs) to differentiate them from the traditional, and more static, corporate websites. Nowadays we can find many RIAs, or simply web applications, across the World Wide Web.

Today, a lot of software as a service (SaaS) with more or less complex user interfaces (UIs) allows us to print our business cards on-demand, watch our favourite movies or live events, order a few pepperoni pizzas for us and our guests, manage our bank accounts from our comfortable sofas, and do many, many other things that make our lives easier.

As CTOs, architects, tech leads, or simply developers, when we start a greenfield project, we can create a single-page application or an isomorphic one (also called a universal application) or work with a bunch of static pages that run in our cloud or on-premise infrastructure.

While we now have such a broad range of options, not all of them are fit for every project.To make the right decision for our projects, we need to understand the challenges we will face along the way.

Before we jump into the topic of this book, let’s analyze the current architectures available to us when we work on a frontend application.

Single-Page Applications

Single-page applications (SPAs) are probably the most used implementations. They consist of a single or a small number of JavaScript files that encapsulate the entire frontend application, usually downloaded upfront.

When the web servers or the content delivery network (CDN) serves the HTML index page, the SPA loads the JavaScript, CSS, and any additional files needed for displaying any part of our application.

Using SPAs has many benefits. For instance, the client downloads the application code just once, at the beginning of its lifecycle, and the entire logic is then available upfront.

SPAs usually communicate with APIs for exchanging data with the persistent layer of the backend. They also avoid multiple round trips to the server for loading additional application logic and render all the views instantaneously during the application life cycle.

Both features enhance the user experience and simulate what we usually have when we interact with a native application for mobile devices or desktop, where we can jump from one part of our application to another without waiting too long.

In addition, an SPA fully manages the routing mechanism on the client side.

Usually, every time the application changes a view, it rewrites the URL in a meaningful way to allow users to share the page link or bookmark the URL for starting the navigation from a specific page. SPAs also allow us to decide how we are going to split the application logic between server and client. We can have a “fat client” and a “thin server,” where the client side mainly stores the logic and the server side is used as persistence layer, or we can have a “thin client” and a “fat server,” where the logic is mainly delegated to the backend and the client doesn’t perform any smart logic but just reacts to the state provided by the APIs.

Over the past several decades, different schools of thought have prevailed on whether fat or thin clients are the better solution.

Despite these arguments, however, both approaches have their pros and cons. The best choice always depends on the type of application we are creating.

For example, I found it very valuable to have a thin client and a fat server when I was targeting cross-platform applications. It allowed me to design a feature once and have all the clients deployed on multiple targets react to the application state stored on the server.

When I had to create desktop applications where the offline persistence layer was an essential feature, I often used a fat client and a thin server instead. Rather than managing the state logic in two places, I managed it in one and used the server for data synchronization.

However, SPAs have some disadvantages for a certain type of application. The first load time is usually longer than for other architectures because we are downloading the entire application instead of only what the user needs to see. If the application isn’t well designed, the download time could become a killer for our applications, especially when they are loaded with an unstable or unreliable connection on mobile devices, like smartphones and tablets.

Nowadays we can cache the content directly on the client in several ways to mitigate the problem. In particular progressive web apps provide a set of new techniques based on service workers, a script that your browser runs in the background separate from a web page for enhancing the user experience of an SPA served on mobile devices with flaky or totally absent connections.

Another disadvantage relates to search engine optimization (SEO). When a crawler is trying to understand how to navigate the application or website, it won’t have an easy job indexing all the contents served by an SPA unless we prepare alternative ways for fetching it.

Usually, when we want to provide better indexing for an SPA, we tend to create a custom experience strictly for the crawler.

For instance, Netflix lowers its geofencing mechanism when the user-agent requesting its web application is identified as a crawler rather than serving content similar to what a user would watch based on the country specified in the URL. This is a very handy mechanism considering that the crawler’s engine is often based in a single location from which it indexes a website all over the world.

Downloading all the application logic in one go can be a disadvantage as well because it can lead to potential memory leaks when the user is jumping from one view to another if the code is not well implemented and does not correctly dispose of the unused objects. This could be a serious problem in large applications, leading to several days or weeks of application hardening in order to make the SPA code functional.

It could be even worse if the device that loads the SPA doesn’t have great hardware, like a smart TV or a set-top box. Too often I have seen applications run smoothly on a MacBook Pro quad-core and then fail miserably when running on a low-end device.

SPAs last disadvantage to mention is on the organizational side.

When an SPA is a large application managed by distributed or colocated teams working on the same codebase, different areas of the same application could end up with a mix of approaches and decisions that could confuse team members.

As well, the communication that overhead teams use to coordinate between themselves is often a hidden cost of the application.

We often completely forget about calculating the inefficiency of our teams, not because they are not capable of developing an application but because the company structure or architecture doesn’t enable them to express in the best way possible, slowing down the operations, creating external dependencies and overall generating friction during the development of a new feature.

Isomorphic Applications

Isomorphic, or universal, applications are web applications where the code between server and client is shared and can run in both contexts.

This technique brings some benefits when used correctly. It is particularly beneficial for the time to interaction, A/B testing, and SEO.

Isomorphic applications can be designed in different ways.

These web applications share code between server and client, allowing the server, for instance, to render the page requested by the browser, retrieve the data to display from the database or from one or multiple APIs, aggregate it together, and then pre-render it with the template system used for generating the view in order to serve to the client a page that doesn’t need additional round trips for requesting data to display.

Because the page requested is pre-rendered on the server and is partially or fully interpreted on the backend, the time to interaction is enhanced. This avoids a lot of round trips on the frontend, so we won’t need to load additional resources (vendors, application code, etc.) and the browser can interpret a static page with almost everything inside.

An SEO strategy can also be improved with isomorphic applications, because the page is server-side rendered without the need for additional server requests when served. The crawler will request the page and receive it fully prepared on the server, ready to be indexed by the search engine.

Isomorphic applications share the code between contexts, but how much code is really shared? The answer depends on the context.

For instance, we can use this technique in a hybrid approach, where we render part of the page on the server side to improve the time to interact and then lazy-load additional JavaScript files for the benefits of both the isomorphic application and the SPA. The files loaded within the HTML page served will add sophisticated behaviors to a static web page, transforming this page into an SPA. We can also have a more purist approach, where we always render the page and its state on the server, providing only a page to display for the browser, depending on the complexity of the project we are facing.

With this approach, we can decide how much code is shared on the backend based on the project’s requirements.

For instance, we can render just the views, inlining the CSS and the bare minimum JavaScript code to have an HTML skeleton that the browser can load very quickly, or we can completely delegate the rendering and data integration onto the server, perhaps because we have more static pages than heavy interactivity on the client side. We can also have a mixed approach, where we divide the application into multiple SPAs with the first view rendered on the server side and then some additional JavaScript downloaded for managing the application behaviors, models, and routing inside the SPA.

Routing is another interesting part of an isomorphic application because we can decide to manage it on the server side, only serving a static page any time the user interacts with a link on the client.

Or we can have a mixed approach. We can use the benefits of server-side rendering for the first view, and then load an SPA, where the server will do a macro routing that serves different SPAs, each with its own routing system for navigating between views. With this approach we aren’t limited to template libraries; we can use virtual document object model (DOM) implementations like React or Preact as well. Many other libraries and frameworks have started to offer server-side rendering out of the box, like Vue with Nuxt.js, Meteor, and Angular. We don’t need to have a Node.js backend for working with isomorphic apps, either; we can use the technology we are more familiar with for serving our APIs, like Go or PHP.

As you can see, isomorphic applications won’t have much of an impact on your existing backend technology stack.

The last thing to mention about isomorphic applications is that we can integrate A/B testing platforms nicely without much effort. In the past year or so, many A/B testing platforms had to catch up with the frontend technologies in not only supporting UI libraries like JQuery but also embracing virtual DOM libraries like React or Vue. Additionally, they have to make their platforms ready for hybrid mobile applications, as well as native ones.

The strategy these companies adopted is to manage the experiments on the server side where the developers have full control of the experiments to run on the clients. This is obviously a great advantage if you are working with an isomorphic application because you can pre-render on the server the specific experiment you want to serve to a specific user. Those solutions can also communicate with the clients via APIs in the case of native mobile applications and SPAs for choosing the right experiment.

But isomorphic applications could suffer from scalability problems if a project is really successful and visited by millions of users. Because we are generating the HTML page pre-rendered on the server, we will need to create the right caching strategy to minimize the impact on the servers.

In this case, if the responses are highly cacheable, CDNs like Akamai, Fastly, or Cloudfront could definitely improve the scalability of our isomorphic applications by avoiding all the requests hitting origin servers.

Organization-wise, an isomorphic application suffers similar problems as an SPA whose code base is unique and maintained by one or multiple teams.

There are ways to mitigate the communication overhead if a team is working on a specific area of the application without any overlap with other teams. In this case, we can use architecture like Backends for Frontends (BFF) for decoupling the API implementation and allow each team to maintain their own layer of APIs specific to a target.

Static-Page Websites

Another option for your project is the static-page website, where every time the user clicks on a link you are loading a new static page. Fairly old school, I know, but it’s still in use — with some twists.

A static-page website is useful for quick websites that are not meant to be online for a long period, such as ones that advertise a specific product or service we want to highlight without using the corporate website, or that are meant to be simple and easier to build and maintain by the end user.

In the last few years, this type of website has mutated into a single page that expands vertically instead of loading different pages. Some of these sites also lazy-load the content, waiting until the user scrolls to a specific position to load the content.

The same technique is used with hyperlinks, where all the links are anchored inside the same page and the user is browsing quickly between bits of information available on the website. These kinds of projects are usually created by small teams or individual contributors. The investment on the technical side is fairly low, and it’s a good playground for developers to experiment with new technologies and new practices or to consolidate existing ones.

Micro-Frontends

Micro-frontends are an emerging architecture, clearly inspired by microservices architecture.

The main idea behind them is to break down the monolith into smaller parts, allowing an organization to spread out the work among autonomous teams, whether colocated or distributed, without the need to slow down their delivery throughput.

Encapsulating an API inside a microservice is actually the easiest part. When we realize there is way more to take care of, we will understand the complexity of the microservices architecture that adds not only high flexibility and good encapsulation between domains but also an overall complexity around the observability, automation, and discoverability of a system.

As with other architectures, micro-frontends are not suitable for all projects; nevertheless, they can provide a new way to structure our frontend applications, solving some of the key scalability challenges we have encountered in the past not only from a technical perspective but also from an organizational one.

Too often I have seen great architectures on paper that didn’t translate well into the real world because the creator didn’t take into account the environment (company’s structure, culture, developers skills, timeline, etc.) where the project would have been built.

As Conway’s Law, mentioned in many books, states:

Note

“Any organization that designs a system (defined more broadly here than just information systems) will inevitably produce a design whose structure is a copy of the organization’s communication structure.”

Conway’s Law could be mitigated with the Inverse Conway Maneuver, which recommends that teams and organizations be structured according to our desired architecture and not vice versa.

I truly believe that mastering different architectures and investing time on understanding how many systems work allow us to mitigate the impact of Conway’s Law, because it gives us enough tools in our belt to solve both technical and organizational challenges.

Micro-frontends, combined with microservices and a strong engineering culture, where everyone is responsible for their own domain, may result in a real silver bullet — complex to build but foolproof when used.

Summary

Over the years, the frontend ecosystem has evolved to include different architectures for solving different problems. A piece has been missing, though: a solution that would allow scale projects with tens or hundreds of developers working on the same project. Micro-frontends are that piece.

Micro-frontends will never be the only architecture available for frontend projects. Yet they provide us with multiple options for creating projects at scale.

Our next step will be learning about the principles of micro-frontends, our guidance in the design and development of micro-frontends architectures.

Chapter 2. Micro-Frontend Architectures and Challenges

A note for Early Release readers

With Early Release ebooks, you get books in their earliest form — the author’s raw and unedited content as they write — so you can take advantage of these technologies long before the official release of these titles.

This will be the 2nd chapter of the final book. Please note that the GitHub repo will be made active later on.

If you have comments about how we might improve the content and/or examples in this book, or if you notice missing material within this chapter, please reach out to the author at building.microfrontends@gmail.com.

Micro-Frontends offer many opportunities. Choosing the right one that will lead to success depends on the project requirements, the organization structure, and the developer’s experience.
In all of these architectures, we face some specific challenges in order to succeed, but all of them are bound by similar questions, such as how we want to communicate between micro-frontends, how we want to route the user from one view to another, but most importantly how we identify the size of a micro-frontend.

The last thing we need to mention before going ahead is defining what micro-frontends are:

A micro-frontend represents a business domain that is autonomous, is independently deliverable, and is owned by a team.

The key takeaways in this description are closely linked to the principles behind micro-frontends:

- Business domain representation

- Autonomous code base

- Independent deployment

- Single-team ownership

In this chapter we cover the key decisions to make when we initiate a project with a micro-frontends architecture, we then discuss some of the companies using micro-frontends in production and which approach they decided to take.

Micro-frontends Decisions Framework

There are different approaches for architecting a micro-frontends application, therefore we need to understand which path we want to follow for our project based on the context we operate.
There are some architectural decisions we have to take upfront because they will shape the future decisions we will take alongside the project. Decisions like how to define a micro-frontend, how to orchestrate the different views, how to compose the final view for the user, or how micro-frontends communicate and share data.
These types of decisions are called the micro-frontends decisions framework. It is composed of 4 key areas:

- defining micro-frontends

- composing micro-frontends

- routing micro-frontends

- communicating between micro-frontends

Define Micro-frontends

Let’s start with the first key decision, this will have a heavy impact on the following decisions. We need to identify how we consider a micro-frontend from a technical point of view.
There are 2 possible options here (Figure 2-1):

- Horizontal split: multiple micro-frontends per page

- Vertical split: one micro-frontend loaded per time

Figure 2-1. Horizontal vs Vertocial split

When we approach our architecture with multiple micro-frontends on the same page, multiple teams need to coordinate their effort because each of them is responsible for a part of the view.
In the vertical split scenario, each team is responsible for a business domain like the authentication or the catalog experience. In this case Domain-Driven Design (or DDD) comes to the rescue, not often do we apply DDD principles on Frontend architectures, but in this case we have a good reason to explore it.

DDD starts from the assumption that each software should reflect what the organisation does and we should design our architectures based on domains and subdomains leveraging ubiquitous languages shared across the business.
For instance, the core domain of an application like Netflix is video streaming and the subdomains inside the core domain are the catalogue, the sign up functionality, or the video player.
There are different subdomain types: core, supportive and generic:

- Core Subdomains: these are the main reasons why an application should exist, core subdomains should be treated as a premium citizen in our organizations because they are the ones that deliver values above anything else

- Supporting Subdomains: subdomains related to the core ones but not key differentiators, these subdomains could support the core subdomains but at the same time are not essential for delivering real value to our users

- Generic Subdomains: these are used for completing the platform and often companies decide to go with off the shelf software because it’s not strictly related to their domain. For instance, in a subscription service like Netflix, the payments management is not related to the core subdomain but it is also a key part of the platform in order to have access to the authenticated section.

Let’s break down Netflix with these categories (Table 2-1).

Table 2-1. Subdomains examples

Subdomain type

Example

Core Subdomain

Catalog

Supportive Subdomain

Voting system

Generic Subdomain

Sign in or sign up

Domain Driven Design with Micro-Frontends

Another important term in DDD is the bounded context, it is a logical boundary that hides the implementation details exposing a contract to consume data from the model present in it.
Usually, it translates the business areas defined by domains and subdomains into logical areas where we define the model, our code structure and, potentially, our teams.
Bounded context defines the way different contexts are communicating together by creating a contract between them, often represented by APIs. This allows teams to work simultaneously on different subdomains respecting the contract defined upfront.

Often, in new projects subdomains overlap bounded context because we have the freedom to design our system in the best way possible, therefore we can assign a specific subdomain to a team for delivering a certain business value defining the contract. However in legacy software, the bounded context can accommodate multiple subdomains because often the design of those systems was not thought of DDD in mind.

In the micro-frontends ecosystem, you can find many technical approaches. Some implementations are done with iframes, others with components library, or web components. Often we are spending more time identifying a technical solution without taking into consideration the busines side.
Think about this scenario: 3 teams, distributed in 3 different locations that are working on the same code base.
These teams may go for a horizontal split using iframes or web components for their micro-frontends. After a while, they realized that those micro-frontends in the same view, need to communicate somehow. One of those teams should be responsible to aggregate the different parts inside the a view and is going to spend more time aggregating different micro-frontends in the same view and debugging making sure that everything works properly.
Obviously, this is an oversimplification, it could be even worse when taking into consideration the different time zones, cross dependencies between teams, knowledge sharing, or distributed team structure.
All those challenges could escalate very easily to low morale and frustration on top of delivery delays, therefore we need to be sure the path we are taking won’t let our teams down.
Instead, approaching the project from a business point of view, allows you to create an independent micro-frontend with less need to communicate across multiple subdomains.
Let’s imagine now the same scenario I described before but instead of working with components and iframes, we are working with SPAs and single pages.
This approach allows a full team to design all the APIs needed to compose a view and to create the infrastructure needed to scale the services accordingly the traffic. The combination of micro-architectures, microservices and micro-frontends, provides independent delivery without high risks for compromising the entire system for release in production.
The bounded context helps design our systems but we need to have a good understanding of how the business works, this helps to identify the right boundaries inside our project.
As architects or tech leads, our role is investing enough time with the product team or the customers so we can identify the different domains and subdomains working collaboratively with them.
After defining the bounded context, we will have a map of our system and we need to work together with the technical teams for restructuring (Figure 2-2).

Figure 2-2. Bounded context example

Often I saw companies designing systems based on their teams structure (Conway’s law states “organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”) instead, we need to be flexible enough for adapting the best possible solution to our organization in order to reduce the friction and move faster towards the final goal: having a great product that satisfies our customers (inverse Conway’s maneuver recommends evolving your team and organizational structure to promote your desired architecture.)!

How to define a bounded context

Premature optimization is always behind the corner, this often leads to a decomposition of our subdomains where we split our bounded contexts for accommodating future integrations instead of waiting until we have enough information for making an educated decision.
Considering our business evolves over time, we also need to review our decisions related to bounded contexts.
Sometimes we start with a larger bounded context and after a period of time the business evolves until the bounded context becomes unmanageable or too complex so we decide to split it.
Deciding to split a bounded context could result in large code refactor but at the same time this could simplify the code base drastically providing a speed up of new functionalities and development in the future.
The rule of thumb for avoiding premature decomposition is making the decision in the last possible moment, this way we are going to have more information and clarity on which direction we need to follow. When we define our subdomains, it’s important to engage upfront with the product team or the domain experts inside your organization. They can provide you with the context of where the system operates. Always begin with data and metrics. For instance, we can easily find how our users are interacting with our application, what the user journey is when a user is authenticated and when it’s not. Data is the most powerful way to have clarity when identifying a subdomain, and it can help to create an initial baseline from where we can see if we are improving the system or not.
If there isn’t much observability inside our system, let’s invest time to create it, it will pay back the moment we start identifying our micro-frontends.
Without dashboards and metrics we are blind in the way our users operate inside our applications.
Let’s assume we see a huge amount of traffic consulting the landing page, then 70% of those users are moving to the authentication journey (sign in, sign up, payment…), from here only 40% of the traffic subscribes to a service or use their credentials for accessing the service.
Those are good indications about our users’ behaviours in our platform, DDD would suggest starting from the domain model of our application identifying the subdomains and their related bounded context and having behavioural data supports us on how to “slice” the frontend applications.
Allowing 100% of our users to download only the code related to the landing page will allow them to have a faster experience because they won’t download the entire application immediately and the 30% of users who won’t move forward to the authentication area will have just enough code downloaded for understanding our service.
Obviously, mobile devices with slow connections can only benefit from this approach for multiple reasons: less KB to download, less memory used, less Javascript to parse and execute and a faster first interaction of the page.
It’s important to remember that not all user sessions contain all the URLs exposed by our platform, therefore a bit of research upfront can only help us to provide a better user experience.

Micro-frontends composition

There are different approaches for composing a micro-frontends application, which can be summarized by the following diagram (Figure 2-3):

Figure 2-3. Micro-frontends composition diagram

In this diagram we can spot three different ways to compose a micro-frontends architecture:

- Client-side composition

- Edge-side composition

- Server-side composition

Starting from the left of our diagram, we have a client-side composition where an application shell loads multiple micro-frontends directly from a Content Deliery Network (CDN) or from the origin if the micro-frontend is not yet cached at the CDN level. In the middle we compose the final view at the CDN level, retrieving our micro-frontends from the origin and delivering the final result to the client. The last diagram on the right shows a micro-frontends composition at the origin level where our micro-frontends are composed inside a view, cached at the CDN level, and finally served to the client.

Let’s now see how we can technically implement this architecture:

Client-Side Composition

In this case, an application shell loads micro-frontends inside itself, these micro-frontends should have as an entry point a JavaScript or HTML file so the application shell can dinamically append the DOM nodes in the case of an HTML file or initialising the JavaScript application when the entry point is a JavaScript file.
Another possible approach is to use a combination of iframes for loading different micro-frontends, otherwise we could use a transclusion mechanism on the client side via a technique called client-side include. Client-side include lazy-load components substituting empty placeholder tags with complex component. For example, a library called h-include uses placeholder tags that will create an AJAX request to a URL and replace the innerHTML of the element with the response of the request.
This approach gives us many options but using client side includes has a different effect than using iframes.

Note

According to Wikipedia, in computer science, transclusion is the inclusion of part or all of an electronic document into one or more other documents by hypertext reference. Transclusion is usually performed when the referencing document is displayed, and is normally automatic and transparent to the end user. The result of transclusion is a single integrated document made of parts assembled dynamically from separate sources, possibly stored on different computers in disparate places.

Edge-Side Composition

With edge-side composition, we assemble the view at the CDN level. Many CDN providers give us the option of using an XML-based markup language called Edge Side Include (or ESI). ESI is not a new language; it was proposed as a standard by Akamai and Oracle, among others, in 2001. The reason behind ESI was the possibility of scaling a web infrastructure to exploit the large number of points of presence around the world provided by a CDN network, compared to the limited amount of data center capacity on which most software is normally hosted. One of the drawbacks of this implementation is that ESI is not implemented in the same way by each CDN provider; therefore, a multi-CDN strategy, as well as porting our code from one provider to another, could result in a lot of refactors and potentially new logic to implement.

Server-Side Composition

The last possibility we have is the server-side composition, which could happen at runtime or at compile time. In this case, the origin server is composing the view by retrieving all the different micro-frontends and assembling the final page. If the page is highly cacheable, it will then be served by the CDN with a long time-to-live policy; instead, if the page is personalized per user, it will require serious consideration regarding the scalability of the eventual solution, when there are many requests coming from different clients. When we decide to use server-side composition we need to analyse deeply the use cases we have in our application and if we decide to have a runtime composition we need to have a clear scalability strategy of our servers in order to avoid down-time for our users.

After understanding the possibilities in front of us, we need to decide which technique is more suitable for our project and the structure of our team. No one is stopping us from a mix of approaches; as we are going to learn later on in this journey, we have the opportunity to deploy an architecture that exploits both client-side and edge-side composition, and that’s absolutely fine as long we understand how to structure our project.

Routing micro-frontends

An important decision when we start a micro-frontends architecture is how we want to route the application views.
This decision is strictly linked to the micro-frontends architecture we intend to use for implementing the project.
We can decide to route the page requests in the origin, on the edge or at client-side (Figure 2-4).

Figure 2-4. Micro-frontends routing diagram

When we decide to compose micro-frontends at the origin, we are forced to route the requests at origin if the page is not cached at CDN level. We might decide to orchestrate at CDN level with an edge computation solution mainly if we have to mitigate any scalability issue that instead we may face at origin level, but on the edge the load would be managed by the CDN provider.
Bear in mind that working with edge computing has its own limitations and challenges, for instance code execution time is finite compare to what we can achieve at origin. External configurations are more complicated because our code can run on multiple locations therefore loading at runtime a configuration from a specific location could add latency to the browser responses when the point of presence is far from the location where the configuration is stored.
Usually there are limits on the amount of edge computations we can run simultaneously from an account.
However, we need to take in consideration that scaling an infrastructure could be non trivial in particular when we have to manage burst traffic with many requests per second (RPS) therefore our servers need to keep up with all the requests and scaling horizontally very rapidly, then each application server needs to retrieve the micro-frontends needed for composing page to be served.
We can mitigate this problem with the help of a CDN, the main problem is when we have dynamic or personalised data where we won’t be able to extensively rely on the CDN serving our pages because the data would be outdated or not personalised.

When we decide to use edge-side composition in our architecture, the routing is based on the page URL and the CDN serves the page requested assembling the micro-frontends via transclusion at edge level.
In this case we won’t have much room for creating smart routing therefore we need to bear this in mind when we pick this architecture.

Another option is using a client-side routing. In this case we need to load our micro-frontends according to the user state, for instance loading the authenticated area of the application when the user is already authenticated or just a landing page if the user is accessing our application for the first time.
If we use an application shell that loads a micro-frontend as single page application, the application shell is responsible for owning the routing logic, therefore at the beginning, the application shell retrieves the routing configuration and then decides which micro-frontend to load.
This is a perfect approach when we have a complex routing of our micro-frontends based on authentication, geo-localization or any other sophisticated logic we want to apply for loading our micro-frontend. Instead, when we are using a multi page website, micro-frontends may be loaded via client-side transclusion. The routing logic that applies to this kind of architecture is almost none because the client relies completely on the URL typed by the user in the browser or the hyperlink chosen in another page, similar to what we have when we use edge-side include approach.
In both cases, we won’t have any scalability issue, the client-side routing is highly recommended when your teams have stronger frontend skills so it becomes natural having a client-side routing over a backend configuration.

Those routing approaches are not mutually exclusive, as we are going to see later on in the book, we can combine those approaches using CDN and origin or client-side and CDN together.
The important thing is how we want to approach the routing of our application because it is a fundamental decision we need to take before starting the development of our micro-frontends application.

Micro-frontends communication

In an ideal world we don’t need to communicate between micro-frontends because all of them are self-sufficient. In reality it’s not always possible notify other micro-frontends about a user interaction, in particular when we work with multiple micro-frontends in the same page.
When we decide to have multiple micro-frontends on the same page, the complexity of managing a consistent and coherent user interface for our users may be non trivial. That is also true when we want a communication between micro-frontends owned by different teams. Bear in mind that each micro-frontend should be unaware of the others on the same page, otherwise we are breaking the principle of independent deployment.
In this case, we have a few options for notifying other micro-frontends that an event occured, we can inject an eventbus in each micro-frontend and notify the event to every micro-frontend, if some of them are interested in the event dispatched, they can listen and react to itt (Figure 2-5).

Figure 2-5. Event emitter and Custom Events diagram

Tip

An Eventbus is a mechanism that allows different components to communicate with each other without knowing about each other.

For injecting the eventbus we need the container of all the micro-frontends to instantiate the eventbus and inject inside each micro-frontends that compose the page.
Another solution could be using Custom Events.
In this case the custom events should be dispatched via an object available to all the micro-frontends, like the window object for instance. If you decide to implement your micro-frontends with iframes, using an eventbus would allow you to avoid challenges like which window object you should use from inside the iframe, considering each iframe has its own window object. Whether we have a horizontal or a vertical split of our micro-frontends, we need to decide how to pass data between views. Imagine we have a micro-frontends for signing in a user and another one for the authenticated part of our platform.
The sign in micro-frontend, after successfully being authenticated, has to pass a token to the authenticated area of our platform. So how can we pass the token from one micro-frontend to another? In this case we have several possibilities.
We can use a web storage like session or local storage, or use cookies (Figure 2-6). So in the scenario presented before we could use the local storage for storing and retrieving the token independently. The micro-frontend is loaded because the web storage is always available and accessible if the micro-frontends live in the same subdomain.

Figure 2-6. Sharing data between micro-frontends in different views

Another option could be passing some data via query strings and retrieving the full details to display via an API (Figure 2-7). Using query strings is not the most secure way to pass sensitive data like passwords or user IDs. In fact there are ways to retrieve that information if passed via HTTPS protocol. Therefore this solution should be embraced carefully.

Figure 2-7. Micro-frontends communication via querystrings or URL

To summarize, the micro-frontends decisions framework is composed of 4 key decisions: identifying, composing, routing, and communication.
In this table you can find all the combinations available based on how you identify a micro-frontend.

Table 2-2. Micro-frontends Decisions Framework summary

Micro-frontends definition

Composition

Routing

Communication

Horizontal

Client-side
Server-side
Edge-side

Client-side
Server-side
Edge-side

Event Emitter
Custom Events
Web storage
Query strings

Vertical

Client-side
Server-side

Client-side
Server-side
Edge-side

Web storage
Query strings

Micro-Frontends in Practice

Although micro-frontends are a fairly new approach in the frontend architecture ecosystem, they have been used for a few years at medium and large organizations.
Let’s start by mentioning a few companies that have worked with this approach in the past few years, because there are many well-known companies that made micro-frontends their main system for scaling their business to the next level.

The first one worth mentioning is Zalando, the European fashion and e-commerce company. I attended a conference presentation made by their technical leads, and I have to admit I was very impressed about what they have created, and released open source.
More recently, Zalando is replacing the well-known OSS project called Tailor.js with Interface Framework based on similar concepts to Tailor.js but more focused on components and GraphQL instead of Fragments as used before.

Another company is HelloFresh, a digital service that provides ready-to-cook food boxes with a variety of recipes from all over the world.
HelloFresh took inspiration from Zalando’s work and are now serving a multitude of SPAs orchestrated by URL.
In an interesting approach to flexibility of components, SPAs are assembled and rendered on the servers, then cached at the CDN level, this allows a good flexibility for generating those SPAs.
In addition, this approach allows the development teams to be responsible for their own technology stacks; each SPA could have a different one, and each team is fully independent from the others.

In 2016, Polish e-tailer and auction site AllegroTech, came up with OpBox, a project that allows non technical people to merge UI representations (aka components) with data sources inside the same page.
At first, they tried to work with multiple components assembled at runtime with ESI lang, but the system didn’t provide the level of consistency they were looking for. Furthermore, they had a few problems for managing specific library versions; for instance a component could have been developed with React v13 and another one with v15 both rendered on the same page.
In OpBox project, Allegro’s teams had the opportunity to decouple the rendering part of a component (the view) from the data to render. As long the contract between the component and the data source matched, they were able to assemble data and different components together, which enhance their ability to do A/B testing and gather data from there.

The thing that stands out from this implementation is the additional abstraction between how the page is composed and the components to display. In fact, a JSON file describes the page and the components needed, and the renderer then composes the page as configured inside the JSON file.
Obviously two or more components on the same page could also react to a specific user interaction or to a change in a set of data, thanks to an eventbus implementation that signals the change to all the components that are listening to it.

In this list of case histories, I can’t neglect to mention Spotify.
For the desktop application, they have assembled multiple components living in separate iframes that communicate via a “bridge” for the low-level implementation made with C++.
Inspecting a Spotify desktop application, we can easily find the multiple parts that are composing this application. Each single .spa file is composed by an html file, multiple css files, a manifest.json and a JavaScript bundle file minimized and optimized (Figure 2-8).

Figure 2-8. Spotify Micro-frontend artifact

Those files will be loaded inside an iframe to compose the final application UI.
This approach was used at the beginning for the web instance of the Spotify player, but due to its poor performance it was abandoned, and Spotify moved back to an SPA architecture like they have for the TV application. This doesn’t mean the approach can’t work but in the way it was designed caused more issues for the final users than benefits.

In fact, another company is using iframes for their applications, like SAP. SAP released luigi framework that is a micro-frontends framework used for creating enterprise application interacting with SAP. Luigi works with Angular, React, Vue and SAPUI, basically the most modern and well adopted frontend frameworks plus a well-know one, like SAPUI, for delivering applications interacting with SAP. Considering enterprise application are B2B solutions where SEO and bandwidth are not a problem at all, having the possibility to choose the hardware and software specifications where an application runs make easy the iframes adoption. In particular if we think the memory management provided by the iframes out-of-the-box, the decision of using them make a lot of sense for that specific context.

Another interesting approach is OpenTable’s Open Components project, embraced by Skyscanner and other large organizations and released open source.
Open Components are using a really interesting approach to micro-frontends in which a registry, similar to Docker registry, gathers all the available components that are encapsulating data and UI, exposing an HTML fragment that can be encapsulated in any HTML template.
This technique brings many benefits to a project such as the team’s independence, the rapid composition of multiple pages by reusing components built by other teams and the option of rendering a component on the server or on the client.
When I have spoken with people who worked at OpenTable, they have shared that this project allowed them to scale their teams around the world without creating a large communication overhead. For instance, using micro-frontends allowed them to smooth the process by repurposing parts developed in the United States for use in Australia — definitely a huge competitive advantage.

Last but not least, DAZN a live and video-on-demand sports platform that is using a combination of SPAs and components orchestrated by a client-side agent called bootstrap.
DAZN’s approach was focused on targeting not only the web but also multiple smart TVs, set-top boxes, and consoles.
Their approach is fully client side with an orchestrator always available during the navigation of the video platform to load different SPAs at runtime when there is a change of business domain.

Those are just some of the possibilities that micro-frontends offer for scaling up our colocated and/or distributed teams. This wasn’t an exhaustive list of use cases because more and more companies are embracing this paradigm such as New Relic, Starbucks, Microsoft and many others.

Summary

In this chapter we discovered the different high-level architectures for designing a micro-frontends applications. We dived deep into the key decisions to take for size, orchestrating, and communicating between micro-frontends.
Finally, we discovered that many organizations are already embracing this architecture in production with successful software not merely available inside the browsers, but also in other end uses, like desktop applications, consoles, or smart TVs.
It’s fascinating how quickly this architecture has spread across the globe for scaling our teams. In the next chapter I will discuss how to technically develop micro-frontends providing real examples you can use within your own projects.

Appendix A. What does the community think about micro-frontends?

A note for Early Release readers

With Early Release ebooks, you get books in their earliest form — the author’s raw and unedited content as they write — so you can take advantage of these technologies long before the official release of these titles.

This will be an appendix of the final book. Please note that the GitHub repo will be made active later on.

If you have comments about how we might improve the content and/or examples in this book, or if you notice missing material within this chapter, please reach out to the author at building.microfrontends@gmail.com.

Throughout this book, we have discussed what micro-frontends are, how we can create a micro-frontends architecture, and what the socio-technical impact of this paradigm is.

Note

As explained in Chapter 1, many companies implemented micro-frontends in production in many different ways.

I interviewed several industry professionals who are embracing micro-frontends in their organizations to share the breadth of uses.

Following are interviews with tech leads, architects, and developers sharing their development challenges with micro-frontends projects.

Enjoy the interviews!

Please introduce yourself.

I’m Felipe Guizar, a senior software engineer at Wizeline. I have over five years of experience working mainly with content publishing platforms for big media companies.

What is your experience with micro-frontends?

I haven’t had the opportunity to implement micro-frontends in a greenfield project yet. However, I’ve worked on several projects that migrated websites to new technologies.

On those projects, we agreed that migrating from scratch was not a good business approach because we can’t deliver new features until we finish the migration. Instead,we decided to look for an approach to gradually migrate the websites and set the basis for integrating new features easily, introducing micro-frontends to our solutions.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

Context:

Frontend technologies (FE) evolve very fast. For instance, I’ve seen companies that started developing their applications using old frameworks/libraries (AngularJS, BackboneJS) years ago. At some point, new frameworks were introduced in the FE world (React, VueJs), and then developers started learning and choosing those as their main tech stack.

For those companies, it’s difficult to keep developers engaged and hire developers who are glad to maintain applications using old technologies.

Benefits:

Micro-frontends help to evolve applications along with the technologies. However, it’s not only about bringing the application up to date in terms of technology; it’s also about aligning the company tech stack with the developer’s expertise.

Pitfalls:

This architecture adds more complexity for managing different pipelines, versioning and integrating the micro-frontends in the host application. Additionally, managing authentication is one of the trickier parts.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

Yes, I’m the creator of Ara Framework.

Ara Framework makes developing micro-frontends easier by integrating any view library (React, VueJS, Svelte) on any web technology/framework, such as NuxtJS, GatsbyJS, WordPress, Flask, and more.

When would you suggest using micro-frontends, and when we should avoid them?

I believe having good knowledge of the business domains is necessary to identify each micro-frontend’s boundaries; otherwise, it leads to bad abstractions that can introduce more complexity for integrating and communicating them.

At the end of your last micro-frontends project, what worked and what didn’t?

Server-side includes using a proxy server works well for integrating non-authenticated micro-frontends in non-JavaScript frameworks. This approach helps us to migrate partial views from WordPress to React along with the content necessary to render those views.

In the early days of the project, we tried to use authenticated micro-frontends using server-side rendering through the SSL proxy server (Nova Proxy). We faced issues forwarding the authentication header, but we realized we could just render those views from the client side using a kind of client-side includes (Nova Bridge).

https://ara-framework.github.io/website/docs/nova-architecture

https://ara-framework.github.io/website/docs/nova-bridge

Also, centralizing the SSL proxy server created the main point of failure. We tackled it by using the server as a sidecar proxy.

https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar

What are the must-have tools for developers to have an efficient experience with micro-frontends?

A command-line interface (CLI) for scaffolding, running services locally, and easily deploying micro-frontends.

For example, Ara Framework has a CLI to create new micro-frontends for different view libraries, and commands to run Nova Proxy and Nova Cluster locally.

What would you suggest for a person who wants to embrace this architecture?

Evaluate the problems you’re trying to solve against the challenges you’ll face implementing this architecture.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?

It encouraged developers to be more involved in the business side, promoting a common language that improves communication. It also encouraged developers to be more involved in making architectural decisions.

However, when micro-frontends were announced in 2019 in the ThoughtWorks Radar as an “adopt technique” in the social networks, there were some misunderstandings about the main goal of micro-frontends. It’s still challenging to introduce the architecture to developers biased by those comments.

What was the developer experience like in your last project?

As I mentioned before a CLI tool significantly improves the developer experiences. However, we needed to extend the Ara CLI to automate deployments and provisioning infrastructure necessary to run the application.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

I believe performance issues related to loading several micro-frontends views on the same page is a sign that micro-frontends boundaries are not well defined. A user flow can involve several subdomains but the user only interacts with one at a time. For example, when a user navigates to the product listing page (product subdomain) and chooses a product, they finally go to the payment page (payment subdomain).

I recommend lazy-loading each micro-frontend entry point based on routing (routes usually represent a subdomain involved in a user flow).

Obviously, there are cases when we have several subdomains on the same page. For example, in an article page, we have the content itself (content subdomain) and the comments and rating section (content feedback subdomain). Users mainly view an article to read the content. Micro-frontends give us the flexibility to server-side render the content and make it available as soon the user opens the page, and we can let the browser client-side render the other sections on demand (lazy-loading based on scrolling).

Regarding design consistency, I suggest using design systems with reusable components that are domain agnostic. Atomic design is a good methodology for implementing design systems in micro-frontends.

What are the first steps for working with micro-frontends?

Define the micro-frontends’ boundaries based on the business subdomains, and identify subdomains that interact together in the user flows.

Can you share the main thing to avoid when working with micro-frontends?

Avoid thinking of micro-frontends as components we can deploy and integrate independently (we can use Module Federation instead). Micro-frontends are views that represent a business subdomain.

What are the main challenges in embracing this architecture from your perspective?

- Identifying the business subdomains and defining the micro-frontend boundaries

- Looking for an approach to aggregate them in the host application

- Handling authentication and authorization

Would you like to share some useful resources about micro-frontends?

- Luca’s resources: https://medium.com/@lucamezzalira/micro-frontends-resources-53b1ec7d512a,

- Ara’s articles https://ara-framework.github.io/website/blog/

- My articles: https://medium.com/js-dojo/micro-frontends-using-vue-js-react-js-and-hypernova-af606a774602; https://medium.com/js-dojo/serverless-micro-frontends-using-vue-js-aws-lambda-and-hypernova-835d6f2b3bc9; and https://itnext.io/strangling-a-monolith-to-micro-frontends-decoupling-presentation-layer-18a33ddf591b

- This curated list of resources: https://github.com/rajasegar/awesome-micro-frontends

Micro-frontends in three words…

Evolutionary, resilient, agile

Please introduce yourself.

I’m Anthony Frehner. I currently work as a frontend architect, which means I have the privilege of working on just about anything related to the frontend :). I’ve spoken at React Rally, I’m helping drive the W3C CSS proposal for “vhc” units (name subject to change), and I’m a core-team member of single-spa. You can find me on GitHub at github.com/frehner and Twitter at twitter.com/aahfrena.

What is your experience with micro-frontends?

I was introduced to micro-frontends (MFEs) when I joined CanopyTax, which is the company where Joel Denning and Bret Little (the creators of single-spa and related tools) worked. It was an amazing transition to be in a place where anywhere from six to twelve — depending on the situation — squads were able to work autonomously. (Squads is a term that was taken from the Spotify model, but essentially they’re full teams that are centered around a feature instead of being organized by role.)

I left Canopy because another company was interested in setting single-spa up for two reasons: 1) to enable future growth and scale, and 2) to help gradually sunset their legacy application and write new code, while running both side-by-side. I like to think we were successful at both, and the company was later acquired.

I think that was one of the first implementations of single-spa which used SystemJS 3.0 with import maps, so it was fun to see how these new standards greatly simplified the infrastructure required for single-spa. That infrastructure would also later help form the foundation for single-spa’s “recommended setup.”

My current company is currently investigating using single-spa because it acquired a company that built a tool in a different frontend framework than the one we use, and we would like to potentially integrate the two without having to do a major rewrite of either.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

You’ve heard this a thousand times, but MFEs aren’t a silver bullet. That being said, they have some great pros and a couple of cons to be aware of:

Pros:

- Team/squad independence. No release trains, code freezes, merge conflicts, long-lived feature branches, QA frustration with testing environments changing/not changing, etc.

- A shared infrastructure that means that everyone is always on the latest version of a library. For example, designers love it because changes to your style guide go out instantly to the whole app.

- A (variable) amount of freedom to experiment and let the best technologies rise out of those experiments, instead of being stuck on the legacy technology because of either the fear of trying something and it failing or not wanting to rework your whole app.

- Lazy loading built in, which means a better and faster user experience.

- Bundle sizes and speeds comparable to a monolithic app. There’s a misconception that MFEs are significantly bigger and slower than a monolith, and that’s simply not true.

- Ability to seamlessly combine legacy software with new software and to integrate software that may have come through an acquisition with in-house software.

- An amazing developer experience. You only have to run a single MFE locally at a time while all the others can just run their production code. Nearly every single developer that I’ve worked with has mentioned how much better the DX is for them over a monolithic setup.

- For single-spa at least, it’s based on web standards: ES modules, import maps, etc.

- Teams that are focused on vertical slices of the app translates into teams that are specialized and know their feature set really well.

However, there are some cons as well:

- On rare occasions, you will need to do an update on all your MFEs, which is a monotonous task.

- The shared infrastructure can be a double-edge sword. For example, it’s great to have your styleguide update for everyone at the same time, until you accidentally break something and now it’s broken everywhere.

- This is minor, but you need to ensure that your CSS is scoped so that one MFE’s CSS doesn’t conflict with another’s.

- The infrastructure takes a bit more work than just building a monolith. However, to put it into perspective, in my experience the vast majority (~90%) of DevOp’s time was spent working on the backend’s microservices infrastructure

Did you contribute to any OSS projects related to micro-frontends? If so, which one?

I’m a core-team member of single-spa, so I’ve worked on the library itself as well as the documentation, browser plugin, example repos, and so on, and I am active in the Slack channel. I’ve been a participant in other projects related to MFEs, namely SystemJS, the Import Map specification, and webpack’s Module Federation plugin.

When would you suggest using micro-frontends, and when we should avoid them?

I generally don’t recommend them for small teams of one to five developers. That being said, there are still situations where that can make sense. Beyond that, it really comes down to how comfortable (or willing to learn) you are with frontend architecture, such as CI/CD pipelines and webpack/rollup configurations.

At the end of your last micro-frontends project, what worked and what didn’t?

Almost everything went well, except for one thing: the decision to support multiple frameworks by using web components. In practice that turned into everyone still only using one framework, but at the cost of additional time and overhead to support web components instead of using framework-specific components. My recommendation is to stick to just one framework when at all possible.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

With single-spa, it’s really just about getting the infrastructure up and running; after that, the tools used on a day-to-day basis are exactly the same as a monolith.

For the infrastructure, you need to understand import maps and webpack/rollup configuration and have a way to scope your CSS.

It’s also important to understand coupling and cohesion and how they relate to microservices. You want MFEs that are highly cohesive and have low coupling in order to succeed.

What would you suggest for a person who wants to embrace this architecture?

Ask yourself for what purpose do you want this infrastructure: If you’re doing it because you’re a small team but you want independent deploys, it may not be worth the effort.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?
When I’ve had genuine conversations with developers about it, they generally are open to the idea but don’t know how to set it all up in practice. After helping them out, they’re almost always excited about it all and love it.

I’ve had conversations with people that are very hesitant about certain aspects (e.g. “the infrastructure is difficult” or “what about consistent styles?”) and the conversations generally go well, even if they still decide to not implement them. That’s ok! Not everyone is up to the task of spending a couple days to work on infrastructure, but at least some misconceptions were dispelled.

And then there’s been conversations with people who are completely unwilling to listen and just want to make memes about MFEs. In those situations, there hasn’t been much I could say that would help them understand.

What was the developer experience on your last project?

Excellent. There are open source tools for doing MFE overrides with single-spa, so that makes working on a MFE easy. Additionally, running only a portion of your whole app locally means that when you hit the save button, webpack takes only a fraction of a second to update instead of multiple seconds to recompile.

Many developers are concerned about performance and design consistency with micro-frontends, what are your suggestions for overcoming these challenges?

Regarding performance, you mainly just need to put constraints on your team\, such as saying “We’ll only support Vue, not any other framework.” Just doing that will take care of 90% of your performance issues; the other 10% is no different than taking care of performance for a monolith.

As far as design consistency goes, that’s actually a strawman put up by people who haven’t used modern MFEs. You’ll find that your designs will actually be more consistent when you only have to deploy your styleguide once and it’s updated for all apps everywhere, instead of needing to npm-install your style guide in each app.

What are the first steps for working with micro-frontends?

Go to one of the example websites that exist for single-spa, and set up an override for one MFE. Try it out, and see what you like and don’t like. Then find us on GitHub, Twitter, or on Slack and ask questions.

Can you share the main thing to avoid when working with micro-frontends?

Just because you can have multiple frameworks, doesn’t mean you should. It’s still recommended to try and stick to one framework if at all possible.

What are the main challenges in embracing this architecture from your perspective?

Your willingness to be open to new ideas, and to work on infrastructure such as CI/CD pipelines and webpack/rollup. You also need to understand when you should create a new MFE versus adding to an existing one.

Would you like to share some useful resources about micro-frontends?

We try to keep the single-spa website up to date. Also, the single-spa Slack channel is open to anyone, and we frequently talk about tech-related things besides single-spa in the #randomstuff channel. The book Building Microservices is a good reference, even though it’s very backend focused.

Micro-frontends in three words…

Enables team independence

Please introduce yourself.

Joel Denning, frontend software dev and independent consultant. I’ve authored single-spa and maintain a lot of other open source, too. I made more than 4,000 GitHub contributions in the last year.

What is your experience with micro-frontends?

I’ve implemented micro-frontends at five companies, and consulted with several dozen more. I created several example repositories (github.com/vue-microfrontendss, github.com/react-microfrontends, github.com/polyglot-microfrontends). I talk to people every day in the single-spa Slack workspace and GitHub issue queues about implementing micro-frontends.

Which benefits and pitfalls did you encounter in your journey with micro-frontends?

Pros:

1. Independently deployed micro-frontends are a huge organizational win. This is the primary benefit in my opinion.

2. Incremental migration between frameworks, with “strangler pattern.” If you can convert your existing app into a Micro-Frontend, you can start adding new micro-frontends without rewriting the old one. This lets you introduce the new framework without the cost of rewriting everything.

3. Ability to hire developers with a larger range of talents, since they can work in more technologies rather than living with the one set chosen for a monolith.

4. Ability to use the “best tool for the job.” Does that React library solve everything? Use it. Does that Vue library solve everything? Use it.

Cons:

1. Conceptual complexity. It takes a while to explain what’s going on to everyone.

2. Technical complexity. Separate CI processes, in-browser module loader, Module Federation, and so on.

3. Possibility for duplicated dependencies between micro-frontends, which is worse for performance than a single monolithic build. There are solutions to this, but they are often not implemented perfectly.

4. Deployment dependencies between micro-frontends are a new thing to consider that don’t exist if you have a single deployable.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

Yes, single-spa and all its helper projects (single-spa-react, single-spa-vue, single-spa-angular, import-map-deployer, import-map-overrides, systemjs, etc.).

When would you suggest using micro-frontends and when we should avoid them?

Use micro-frontends when:

- You’re trying to migrate away from an old framework or monolith.

- You want independent deploys for separate dev teams.

- You want some level of independent technical decision-making for separate dev teams (which date formatting lib to install, which react css lib, or perhaps even which UI framework).

- You want to split your UI into highly cohesive, loosely coupled sections. This comes from the Building Microservices O’Reilly book.

Avoid micro-frontends when:

- You don’t want to do micro-frontends.

- Your monolith is working well for you.

- There is only one dev on the project.

- Separate deployments cause more pain than benefit, due to deployment dependencies. This occurs especially when you have very few developers.

- Your micro-frontends regularly engage in heavy, chatty communication. If the micro-frontends are talking to each other all the time, perhaps you should not be using micro-frontends.

- Your dev team does not have the technical expertise, time, or desire to manage a more complex system.

At the end of your last micro-frontends project, what worked and what didn’t?

What worked:

- We created a separately deployable project with its own package.json, build, and CI process. This was a huge win over our PHP/Laravel monolith that built react with an old version of node and gulp.

- We were able to free ourselves from many of the technical decisions of the past.

- We were able to create a style guide/component library that lets us collaborate with UX a lot easier.

What didn’t work:

- DevOps was very resistant and took a lot of convincing. The new CI pipelines and infrastructure took a long time to build.

- Some devs confuse micro-frontends with react. They were new to and couldn’t tell what things came from what.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

- import-map-overrides: It allows you to develop one micro-frontend at a time, instead of running all of them locally.

- single-spa: The most popular open source framework for micro-frontends that I’m aware of.

- import-map-deployer: A clear way to achieve independent deployments for your separate projects.

- import maps: A separate name of the micro-frontend from its url. This is important for independent deploys.

- systemjs: For in-browser module and import maps polyfill support.

What would you suggest for a person who wants to embrace this architecture?

Look at your backend code’s architecture and evaluate whether it is working for you. It often makes sense for your backend and frontend architecture to match. If one is a monolith, the other should be. If one is microservices, the other should also be microservices.

Look at how your organization gets things done. If your organization’s culture is geared toward product ownership, team autonomy, and distributed decision-making, then micro-frontends might make sense. If it’s more of a centralized decision-making process, then it might not make sense.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?

Where are the lines between micro-frontends and a UI framework? What is doing what? How do the pieces fit together? What does this repo (or that repo) do? What’s the mental model for the whole system?

What was the developer experience on your last project?

See https://github.com/joeldenning/import-map-overrides. You do `npm install` and `npm start`. Then you go to a deployed environment and set up an override so that it uses your local version of the micro-frontend instead of the deployed version.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

For shared dependencies, see https://single-spa.js.org/docs/recommended-setup#shared-dependencies

For design consistency, create a shared style guide module and/or choose a design system such as bootstrap. See https://single-spa.js.org/docs/microfrontends-concept#types-of-microfrontends and https://github.com/react-microfrontends/shared-dependencies.

What are the first steps for working with micro-frontends?

1. Create a POC to help you decide whether you want to do it.

2. Convert your existing app to be a single micro-frontend. Release that to production.

3. Pull out shared navigation into its own micro-frontend. Release that to production.

4. Implement your next new feature as its own micro-frontend. Release that to production.

5. Pull out a small part of your monolithic app into its own micro-frontend. Release that to production.

Can you share the main thing to avoid when working with micro-frontends?

- Splitting them up too much or incorrectly, such that they’re all highly coupled

- Shared, single deployment for all your micro-frontends

What are the main challenges in embracing this architecture from your perspective?

1. Converting your existing code into a Micro-Frontend, so that future code can be split into separate micro-frontends.

2. Setting up CI/CD

3. Organizational buy-in, trust, and training

Would you like to share some useful resources about micro-frontends?

This YouTube playlist is great.

Micro-frontends in three words…

Microservices for frontends

Please introduce yourself.

Zack Jackson, principal engineer of lululemon.

I focus on distributed JavaScript application architecture and how to scale a company’s codebase, teams, and platforms. I’m passionately involved in open source! I created the first code-split SSR system for React, and I’m the creator of webpack 5’s flagship feature, Module Federation.

What is your experience with micro-frontends?

I have exclusively built micro-frontend stacks for companies since 2015. The largest stack I’ve built consisted of 150 separate micro-frontends. It consisted of a shared component library; feature-based components used the component library but most features were deployed independently as a micro-frontend. The range of what the micro-frontends were made of was pretty wide. Some were a single component, some were full features, and others were whole pages or user flows.

I designed the Starbucks inventory management platform, used by all its stores. This stack consisted of six separate micro-frontend applications with helper services for authentication.

At lululemon, I am building a powerful stack that leverages an AppShell and Module Federation and that enables drag-and-drop refactors as features or code that can be moved between servers with no need for regression or extra engineering time. I’ve extended Module Federation beyond managing seamless micro-frontend experiences, into analytics, A/B testing, and configuration management — all while remaining standalone and independently deployable at any time providing evergreen code to consumers.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

One pitfall was poor code sharing. Sharing vendor code is manual and primitive, causing centralized dependency on an external set of vendors, and upgrading package versions is complex as breaking changes would require all micro-frontends to be prepared for the upgrade of a shared vendor.

Another was poor UX. When moving between micro-frontends, a page will reload. There are very few solutions to sharing global state or making micro-frontends work as well as a monolithic SPA. Huge amounts of time can go into improving the UX.

The benefits of micro-frontends outweigh the pitfalls at scale. Code can be deployed independently, builds are faster, regressions are easier to run, and the blast radius of a critical failure is well contained. It saves engineering time and company money, as features can be delivered at a fast rate, unlike in a monolith, where the rate of delivery slowly degrades as the codebase increases in size and complexity. Micro-frontends remove the harsh requirement of communication and coordination overhead between teams. They are also cheaper to run and scale because you can use cheaper, less-powerful servers. Unlike a monolith, you can scale per page or per component on cheaper hardware instead of scaling expensive and powerful hardware to meet the base demands and memory consumption of the entire monolith.

Micro-frontends are far more agile and they safeguard companies against site-wide critical failures. Redundancy layers can be built easier, and teams can model a platform to fit their needs instead of using a one-fits-all model that monolithic platforms enforce.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

Next.js, webpack 5 Core, single-spa, React Static, and Module Federation extensions and enhancements.

When would you suggest using micro-frontends, and when we should avoid them?

Small companies will likely not benefit from the engineering overhead. Larger companies with challenges at scale or companies with multiple teams who rapidly deploy are likely best suited to benefit from distributed JavaScript applications.

Regardless of use case and scale, it’s very important to design your platform from the ground up to handle scale. If you foresee rapid scale in the future, designing a system that can be migrated into a distributed application model is key. You’ll save time and money by avoiding a full-scale rewrite.

At the end of your last micro-frontends project, what worked and what didn’t?

Automatic vendor sharing was challenging, routing between the separate apps and making that route transition seamless were a major challenge, and maintaining authentication sessions and sharing state were very challenging as well. My current micro-frontend project has been designed to avoid these issues by rethinking how applications interface with each other and are designed in general.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

Webpack 5 Module Federation is a massive unlock, single-spa provides a strong orchestration layer, Next.js with a custom AppShell, and yarn workspaces that serve as sub-apps is a robust design pattern, which can enable scale and can integrate with Module Federation if or when needed. Micro is another fantastic tool for creating an ingress to route a user to the correct micro-frontend as well. Leveraging monorepos keeps code organized but will still have the pitfall of having only one master branch, bottlenecking deployments. Semantic-release is vital for micro-frontend architecture, where semver plays an important role in the scalability and reliable code distribution.

What would you suggest for a person who wants to embrace this architecture?

Give Module Federation a try. Most importantly, design a system that supports scale. Think about monorepos, feature binding, how bound a page or feature is to a specific server, and how hard it would be to split some of the app into another micro-frontend at a later point in time. Avoid hard binding to a server; build software that can be easily migrated to a new stack. Globals like shared state should encapsulate a page or feature, keeping it independent and unbound to the server. Moving a page or feature to another server instance should be built in a way that will provide any globals needed out the box, not involve multiple copy-pastes of various parts of the application. Gitlab CI is powerful and a strong contender for sophisticated infrastructure requirements.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?

Development time and efficiency usually quadruples. Introducing the pattern has given development teams a better experience and the ability to move more code through the pipeline at a faster rate. Challenges revolved around performance concerns from SRE and getting developers used to working in more than one repo at the same time. In highly granular MFE stacks, it can be a learning curve to run multiple MFEs locally and to get used to having several IDEs open, depending on what feature is being developed.

What was the developer experience on your last project?

Kubernetes, custom router and auth layers, shared global packages, special script to boot and run all MFE’s in one place for full workflow use.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

Webpack 5 Module Federation is the best solution to this problem. There are no performance concerns or design consistency issues. Code is shared at runtime; it’s evergreen.

A non-webpack-5 solution would be to use renovate bot and depend on abstraction for distribution or having the micro-frontends supply a render API to allow other applications to retrieve HTML and other resources over a network call. Ultimately, these are better ways to share feature and vendor code along with automation around upgrading dependencies.

What are the first steps for working with micro-frontends?

Figure out how it’s going to scale. Centralize shared code, utilities, and data calls. Make sure the platform layer does not become fragmented when managing several independent servers. Think about routing and how you will map various routes to their MFEs.

Can you share the main thing to avoid when working with micro-frontends?

Not abstracting core code to npm. Copy pasting server infrastructure, which leads to maintenance challenges and fragmentation at the platform level. Either an application shell or server shell should exist, which holds high-level aspects, like auth, user state, tooling, and translation configurations.

What are the main challenges in embracing this architecture from your perspective?

Avoiding UX degradation in favor of DX improvement, neither should be compromised. Thinking out how your MFE stack is going to look and work in one year’s time with over 10 stacks: does it architecturally scale?

Would you like to share some useful resources about micro-frontends?

https://medium.com/swlh/webpack-5-module-federation-a-game-changer-to-javascript-architecture-bcdd30e02669

Micro-frontends in three words…

Cheap, flexible, scalable

Please introduce yourself.

My name is Erik Grijzen. I’m from The Netherlands, but currently living in Barcelona, Spain where I work for New Relic, a company that has an observability platform that gives its customers insights on how their systems and software are running in real time.

About three years ago, shortly after I joined the company, I’ve been working on a new project to build a completely new platform UI, using a micro-frontend architecture. As of today, I’m still working and evolving this project as a lead software engineer on the team and the technical product manager for the UI of the platform.

I’ve worked as a software engineer for many years in a variety of different companies throughout my career. My focus has always been more on the frontend side of things, which is what I’m most passionate about.

What is your experience with micro-frontends?

My experience with micro-frontends has been solely working on this new platform within New Relic over the last three years. Let me give you some context on how we ended up deciding to use this architecture because I think this is quite interesting and I believe many other companies find themselves in a similar position.

New Relic is a fast-growing company and in the last 10 years, it has built many different products. All these products were built separately as monolithic single-page applications that were linked together through one common navigation. This approach was very successful until more or less three years ago, when we discovered that we had several problems related to the consistency of our user experience, extensibility of our UI, and the way we did UI development within our company. Let me go over each one of these problems to explain them a bit more in depth.

Many of our customers were starting to have more and more complex systems because they were adapting to a microservices architecture and moving towards the cloud. As a result of this, our users were forced to switch constantly between our separate applications to troubleshoot problems in their systems. Despite all the best efforts of our UI engineers, our products were all working and looking slightly different (in some cases very different), which led to undesirable user experiences. On top of that, switching between applications also caused our users to lose the context of the issues that they were troubleshooting, which was an even bigger problem.

The landscape of technology (software, tools, programming languages, integrations, open-source, etc.) that our customers wanted to instrument and observe was (and still is) exploding. It’s almost impossible to keep up, so it was clear that we wanted a new approach where we could provide new functionality for our users in an easy and fast manner. Besides that, we also noticed that some customers had very specific use cases that only applied to them. To also cover these cases, we wanted to provide a way to make our user interfaces programmable so that they could extend the platform for their specific needs.

We also saw that inside our company, many UI engineers were doing a lot of duplicate efforts regarding project setup, tooling, configuration, etc. We wanted to reduce the toil and boilerplate that each team has to go through to build new features so that they could spend more time on building innovative and creative product solutions for our users.

It turned out that a micro-frontends architecture was a perfect fit for us to tackle these problems. Users are demanding more unified product experiences, but it’s not easy to build a product with hundreds of UI engineers at the same time, especially when they are located in different offices around the world and in different time zones. And in our case, allowing customers to build on top of the platform as well made the problem even more difficult. In the end, we decided that a micro-frontend architecture was how we wanted to scale our UI development within our organization.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

In our experience, this architecture has very similar benefits and downsides that you can expect from using a microservices architecture on the backend. However, there are a few exceptions to this due to the nature of how browsers work.

Let’s start with the benefits. I believe the main topics that we should cover where we noticed the biggest differences are the following:

- Team autonomy

- Small and decoupled codebases

- Modeled around a business domain

- Automation and standardization

To scale the UI development inside our organization, the most important thing we wanted to achieve was for teams to work autonomously. They should be able to deploy new code whenever and as many times as they want without depending on any other team. Each team should be cross-functional, meaning they have every role (designer, frontend engineer, backend engineer, QA engineer, etc.) on the team to build the functionality they want, so that they can do a complete end-to-end implementation. This means they have full ownership and can take all the responsibility for one or more related micro-frontends that are part of a specific business domain. This is important because this allows parallel development without slowing down when more and more teams are working on our platform.

To achieve this autonomy from a technical point of view, the micro-frontends must be loosely coupled, so that they don’t depend on each other and whenever they interact they should have clear contracts. Each micro-frontend is also small in size so that they are easier to reason about (you don’t need to know the whole system), easier to test and you can easily add, change or remove them over time.

Our micro-frontends are modeled around a business domain or subdomain, because this aligns better with the structure of our business. It creates fewer team dependencies, gives teams more autonomy, and improves the communication to make quick decisions so that teams can iterate over features faster. To give a more concrete example, one team could be organized around the domain of NodeJS application monitoring. They are highly specialized and are subject matter experts on that topic, which typically results in higher-quality code and better solutions for our end users.

With our micro-frontend architecture setup, we moved from several monolithic single-page applications to many small micro-frontends that are composed at runtime into one unified platform. This resulted in an explosion of a lot of small codebases, which are each owned by separate teams. It was very important to be prepared for this because this architecture introduces a lot of repetitive work and duplication. That’s why it’s very important to have the proper infrastructure, tools, and standardization in place. We automated every step in the development process, from project creation and pipeline build to continuous integration and continuous deployment, basically providing everything that the team needs, so they can focus on building functionality that our users love.

Let’s move now to some of the pitfalls we encountered using micro-frontends. In our journey the two hardest parts were:

- UX consistency

- Performance

Every architecture comes with tradeoffs. I don’t think we have a perfect solution to make the UI always consistent and performant, but we try to mitigate the downsides as much as we can. In most cases, this means putting certain constraints in place and reducing the autonomy of teams. For example, we have a constraint in place that every team should use a specific version of the ReactJS library to build their user interfaces. This obviously limits the teams from using any technology they want, but we think it’s worth it because this constraint reduces the performance costs a lot for our users. We don’t want to limit innovation in the organization, but when we try out new technologies and we carefully evaluate the impact it has on the system, we then update the organization standards and move this innovation to the platform level, so that everyone can benefit from it.

When you have many teams working on the same platform, the consistency of the UI is at risk. To reduce this downside as much as possible, we think it’s critical to at least have a design system in place. This won’t magically make everything consistent, but I think without it, you will definitely be in a world of trouble. In our experience, this design system is best owned and maintained by one team. This doesn’t mean others cannot contribute, but there’s one team making sure it aligns with the bigger picture. We’ve tried an open source model where everyone could contribute to the design system, but this didn’t work out for us, because when everyone is responsible for it, nobody is responsible for it. Maintenance work, bug fixes, and keeping everything aligned with the bigger picture are especially hard to do in this setup. To further improve consistency, we also implemented an SDK that all micro-frontends have access to. This SDK has all the UI components from our design system and provides several APIs to standardize certain patterns such as navigating around the platform.

To make sure our platform stays as performant as possible, we have several things in place. First of all, the platform is built with the application shell model which makes it very minimal and fast loading to achieve a good initial perceived performance for the users. When the platform is loaded, we lazy-load the micro-frontends based on the client-side routing, which allows us to only load the minimal JavaScript and CSS necessary to render the screen. To reduce the payload size of the assets we load and memory consumption of the application, we think it’s necessary to deduplicate the frontend dependencies as much as possible. On the platform level, we provide some dependencies (i.e., ReactJS) that we are sure every micro-frontend is going to need. We do that by defining those dependencies as webpack externals so that these don’t get bundled up for each micro-frontend. This alone reduces the bundle sizes by an incredible amount. For each repository that contains micro-frontends, we are code-splitting the bundles so that we can lazy-load them incrementally at runtime inside the platform. The last thing we do is provide the before mentioned SDK on the platform level by injecting it in each micro-frontend. This reduces the need to use other NPM dependencies, which should decrease bundle sizes even more.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

No, I’m not contributing to any open source projects at the moment. I looked into several of the bigger micro-frontend frameworks and libraries a while back, but none of them really matched with how we wanted this architecture to look like for our platform.

I’ve been asked several times if we will open source what we’ve built at New Relic. Unfortunately, we don’t have any plans to do so. I also think that what we have right now is too tailored for our needs and we would have to change it quite a bit before it would make sense to release it to the public.

When would you suggest using micro-frontends, and when we should avoid them?

Using an architecture like this comes with a lot of tradeoffs that have to be evaluated carefully and need to make sense for your project and company. Typically the benefits outweigh the downsides when you need to scale your UI development to a lot of teams, which normally only happens for mid-sized to large companies. So my recommendation is to not use this architecture for small projects or companies. If you’re not sure you need micro-frontends, you most likely don’t need them. Just start simple; you can always slowly migrate to micro-frontends over time when there’s a need for them.

At the end of your last micro-frontends project, what worked and what didn’t?

I never officially completed a project using micro-frontends. We are continuing to evolve the architecture of the platform as the product and organization change over time. I consider it nearly impossible to get the architecture right from the start, so you are guaranteed to encounter things that are not working as you might expect. Our current architecture is very different than the one we started with three years ago.

What really worked well for us, was to set up some ways to regularly communicate and get feedback from other teams. This was very crucial in adjusting over time and refining the balance on several architectural topics. I think we have been too restrictive in some areas and we had to put some more restrictions in other places to get the results that we wanted. We try to keep a close eye on what’s not working for us and adjust over time to improve the situation.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

This depends on a lot of things because there are many ways you could implement micro-frontends based on the requirements of the project, its business requirements, and how your company is organized. But generally speaking, you want to make it as easy as possible for teams to be successful, whatever that implies in your context.

At New Relic, we’ve built a command-line interface that uses our internal infrastructure and tools to give teams everything they need to develop features fast. Almost everything you can think of is automated, from project creation to the final deployment to production. We are in a very competitive market, so for us, it’s vital to have a fast time to market, be able to quickly iterate on features based on the feedback from the user and spend as little time as possible on technical configuration, setup, and other repetitive boilerplate.

What would you suggest for a person who wants to embrace this architecture?

Micro-frontends are not a silver bullet. Just like with any architecture, there are many tradeoffs to be made. You have to find the right balance between those tradeoffs that works best for your project, company culture, and organization. What typically happens is that you go from one or several big codebases to many small codebases. That’s why I think it’s important as a company to make sure you first have the necessary infrastructure, tooling, and standardization in place to support this architecture before you make the change.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?

I think people don’t talk about this a lot, but introducing micro-frontends can be quite a cultural and organizational change that requires kind of a shift in the way you work. This might come as a surprise sometimes to developers who never worked with such an architecture. For us, this was a change that happened slowly over time, so as more and more teams onboarded to work on top of the new platform, the company and the people slowly transitioned to this new way of working.

Especially for the teams that were building micro-frontends on top of the platform in the early stages, it was not always easy. They didn’t always have everything they needed and there were still dependencies and things that were blocking them from completing their work. This has improved a lot over time, with better communication, documentation, resources, and better tooling in place to support developers from day one.

What was the developer experience on your last project?

To build micro-frontends on top of our platform, you have to use a command-line interface. Both our customers and internal teams can use this to extend the platform with all different kinds of micro-frontends. This CLI automatically takes care of the project setup, pipeline build, continuous integration, and continuous delivery. This allows for very rapid feature development; you can go from idea to production within hours.

When you create a new project it automatically scaffolds the repository with all the required dependencies, structure, configuration, version control, and integration with internal tools. By default there are many NPM scripts configured to take care of typical developer experience, such as local development, linting, prettifying, bundling, testing, and other automated tasks to make sure that what you build will work within the platform. When you do pull requests we automatically generate URLs to test the changes against the platform, which makes code review much smoother. Finally, when a pull request gets merged we automatically create a release for our continuous delivery system, which makes it easy to deploy a specific version to any environment, do rollbacks, and so forth.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

I’ve already explained how we are trying to tackle these two challenges. Like I mentioned before, we don’t have a perfect solution, but we try to reduce the downsides as much as we possibly can in the context of how we implement micro-frontends in New Relic.

My suggestion would be to carefully evaluate the importance of these topics; based on that you can define the appropriate constraints on the autonomy of the teams that are building micro-frontends. The more constraints you put in place, the more you can reduce the downsides. You will probably end up with a middle-ground solution that is best suited for your project and organization.

What are the first steps for working with micro-frontends?

It’s hard to give specific recommendations on how to start working with micro-frontends because this depends so much on the type of project, culture, organization, and the size of the company. The way we have organized, set up, and architectured our UI development with micro-frontends might be a complete disaster for another company.

Some general recommendations when you get started:

- Make sure you find the right balance of trade offs that work for you.

- Make sure to communicate and get feedback, so you can adjust architectural decisions to overcome challenges.

- Make sure you have enough infrastructure, tooling, and standardization in place that supports this architecture.

Can you share the main thing to avoid when working with micro-frontends?

The main goal of micro-frontends is to scale the UI development within the organization. So the main thing to avoid is creating dependencies between teams or blocking the development of teams in any way.

What are the main challenges in embracing this architecture from your perspective?

I think the main challenge is to tackle some difficult tradeoff decisions, where you are forced to choose between the autonomy of teams and the user experience of the end users. This is not always easy, but I think with time you will always find a good middle ground for each of these tradeoffs.

Would you like to share some useful resources about micro-frontends?

If you are reading this, you already have the best resource at hand. I would also recommend the talks that you can find on YouTube from Luca, especially for people that are new to micro-frontends.

Micro-frontends in three words...

Scaling UI development

Please introduce yourself.

David Leitner is co-founder of SQUER Solutions, a Viennese software company, and describes himself as an enthusiastic software professional who works on various projects using a bunch of different stacks and environments. He spends much of his time on the frontlines tackling the challenges of scaling software and complex domains. A software engineer with more than 10 years’ experience, David prefers his code simple and small instead of clever and edgy. David enjoys sharing his knowledge as speaker at conferences, as a podcast co-host, and as a lecturer for his post-diploma courses at the University of Applied Sciences Technikum Vienna.

In 2016 David was one of the first who dealt with the topic of micro-frontends intensively and proposed his ideas to international conferences.

What is your experience with micro-frontends?

When consulting with our customers, we always stress that microservices are about end-to-end verticals that enable independent deployments of autonomous parts of an application at a high pace. Following this idea, it was clear from the very beginning that we had to somehow make this possibility on the frontend parts of these architectures, as well. We experimented in a dozen of projects with different approaches, including simple ones, like linked applications, but also more sophisticated ideas, like the integration on the client side with web components.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

One big lesson was the impact on the look and feel of huge frontend applications. Thus, a Micro-Frontend architecture must go hand-in-hand with a strong understanding and maturity in design systems. In addition, you also have to deal with the classical issues of distributed systems, like performance and latency. For example, over the years we discovered that a shared caching layer on the frontend is a good idea; it was a game changer for how we designed our micro-frontend architectures. And last but not least, it’s nearly always a wise decision to start with a monolith-first approach.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

Unfortunately, I have not actively contributed to one of them so far, mainly because we almost never use off-the-shelf frameworks for our micro-frontend architectures. We try to keep the dependencies small and stuck to basic web standards, like web components, to build micro-frontends.

When would you suggest using micro-frontends, and when we should avoid them?

It’s really hard to answer this question without any further context, but, I think it is important that as with every new architecture or technology, micro-frontends should not be an end in itself. Still, in our experience at SQUER Solutions, it shows its benefits mainly when the team size gets too big to work on one codebase in the frontend, when resilience issues start to erase, or when the time to market is below expectations.

At the end of your last micro-frontends project, what worked and what didn’t?

I think we started to have the maturity that allowed us to spot the right points where the frontend should be split up. But especially for client-side integration, it’s a daily challenge to let the integration module of your micro-frontend architecture not sprawl too big and become a bottleneck.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

In most cases the concept of monorepo makes a lot of sense: a single repo for all the micro-frontend projects, especially to share and ensure consistency for commonly used UI components. Besides this, each module that is used inside the micro-frontend architecture should, of course, strictly follow semantic versioning, and the team should have a common understanding about breaking changes.

What would you suggest for a person who wants to embrace this architecture?

As mentioned before, start with a monolith-first approach. Only start to use micro-frontends once you understand the domain well enough to split them up reasonably.

What was the impact of introducing micro-frontends to developers who didn’t know about them? Which challenges have you faced?

I have seen similarities to the introduction of micro services a few years ago, which makes total sense, as in both cases distributed architectures are introduced. The new challenges are therefore to design micro-frontends to be backward compatible and to enforce asynchronous communication over synchronous one.

What was the developer experience on your last project?

I think a solid CI/CD pipeline is essential. In a micro-fronted architecture, most of the complexity moves from a developer’s machine to the build-and-deployment process. Thus, a feature in such an architecture is delivered once it’s deployed to production, not once it’s committed to the version-control system. All the tooling should support and align with this thinking.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

Basically, it can be said that these concerns are absolutely justified. The question should be whether other advantages of micro-frontends outweigh these problems for a specific use case. My rule of thumb for performance is the more we strive for performance in a micro-frontend architecture, the more we must move the integration to the client. For design consistency, a mature design system can usually overcome most of the challenges.

What are the first steps for working with micro-frontends?

Don’t be too opinionated, search for diverse resources that will help you make decisions. In addition, conference talks are a good source for practitioners’ reports and learning from the mistakes others have already made.

Would you like to share some useful resources about micro-frontends?

As mentioned before, I usually like to listen and learn from the experiences of others; conference videos on YouTube are a good way to get those insights. In addition, the micro-frontend introduction on Martin Fowler’s blog is a good jump start to this topic. Well, and of course the book you are holding in your hands!

Micro-frontends in three words…

Go for it!

Please introduce yourself.

My name is Philipp Pracht. I work as an architect and product owner at SAP, located in Munich, and I’m a proud father and husband.

What is your experience with micro-frontends?

I’m currently working on project Luigi (luigi-project.io), a technology-agnostic micro-frontend framework for admin and business UIs. Before that, I was working on the user interface part of YaaS (a microservice-centric platform and commerce-as-a-service solution), where we successfully established a micro-frontend architecture back in 2014, before the term “micro-frontends” even existed.

What benefits and pitfalls did you encounter in your journey with micro-frontends?

The main benefit is the efficiency boost for any large-scale UI development landscape with multiple teams. In my previous project, I was part of the team responsible for the UI. There were more than 20 teams developing microservices. After we established a micro-frontend architecture (again, it wasn’t called that back then) and asked the service teams to take ownership of their UI parts, I was extremely impressed and surprised by how well it worked out. After a short technical introduction, all teams were able to develop and release completely independently, and we never heard back from most of them. It just worked.

The main pitfalls were not on a technical level but rather with some people who did not really stick to the philosophy of micro-frontends, or even of independent, self-empowered teams in general. Sometimes this led to long-lasting and unproductive discussions.

Did you contribute to any OSS project related to micro-frontends? If so, which one?

Apart from Luigi, which is open source, I contributed to Kyma (kyma-project.io), a platform based on Kubernetes for extending applications with serverless functions and microservices. Luigi started out as a Kyma side project, with the goal of extracting the micro-frontend architecture of Kyma’s admin console into a framework so that it can be reused in other applications. Of course, Kyma is now using Luigi.

When would you suggest using micro-frontends, and when we should avoid them?

In general, there is a correlation between the (predicted) functional scope and the benefits of using a micro-frontend architecture. If you are certain your UI will have a fixed set of UI components and will be developed by only one team, then you should go with a conventional approach. For all other scenarios, you should check if there is a micro-frontend framework out there that can help you. Even small projects can benefit from something like Luigi, as it offers some extra features that go beyond a pure micro-frontend framework.

At the end of your last micro-frontends project, what worked and what didn’t?

On a technical level, everything worked and there were no major issues.

What are the must-have tools for developers to have an efficient experience with micro-frontends?

Tools for reliable development and testing environments are key. Developers should feel confident at all times that what they are currently implementing will work in the bigger context. For example, in my previous project we offered a CLI tool with which developers could run an emulated main application with their micro-frontend included.

An excellent IDE is also a must.

What would you suggest for a person who wants to embrace this architecture?

As with any hype, read about the topic first, then lean back and think about it from different angles. Think about the possible impact for people in different roles and try to come to a good understanding of where micro-frontends would be a good fit — not only from a technical point of view but also when it comes to organization structures and people.

What was the impact of introducing micro-frontends to developers who didn’t know about them? What challenges have you faced?

From my experience with introducing Luigi, developers were happy with it in general. probably because Luigi helps where help is needed but doesn’t impose anything — developers still had full freedom within their boundaries. In my previous project, though, there were situations where developers had problems focusing only on their part.

What was the developer experience on your last project?

In project Luigi, we created a tool called Luigi Fiddle (fiddle.luigi-project.io), a playground where you could try out most of our core functionality. It turned out to be pretty helpful, especially for onboarding new developers.

Many developers are concerned about performance and design consistency with micro-frontends. What are your suggestions for overcoming these challenges?

This depends heavily on the approach you choose, especially the performance topic. For example, Luigi has various mechanisms (like the “viewgroups” concept, caching, preloading) to mitigate performance issues for the end user. With concerns about design consistency, I was a bit surprised when I found out people consider this an issue. I usually ask them how they ensure design consistency in an app that doesn’t use micro-frontends, and the answer is something like “This is not a problem, because we have the same CSS.” Eventually most of them realize that you can also share CSSs across different applications. You could also develop Angular components that are not consistent with the rest of the app, so it is the developer who ensures consistency, because he wants his piece of UI looking good in its context.

What are the first steps for working with micro-frontends?

Think about how you want to subdivide your UI, then have a look at Luca Mezzalira’s micro-frontends decision framework.

Also, check if there is already a framework out there that fits your requirements.

Can you share the main thing to avoid when working with micro-frontends?

Avoid introducing a monolithic layer somewhere else in your stack, because you lose most of the benefits from micro-frontends. Micro-frontends work best with micro services.

From your perspective, what are the main challenges in embracing this architecture?

The main challenge would be if your organization structure isn’t a good fit. Your management has to set up a structure where dedicated units (a single dev team in the easiest case) can independently deliver end-to-end features.

Would you like to share some useful resources about micro-frontends?

All publications from Luca Mezzalira, of course.

There is also a good explanation of micro-frontends on martinfowler.com. And of course you can look at luigi-project.io and our YouTube channel, where you can find luigi-specific content, as well as some general information about micro-frontends.

Micro-frontends in three words…

Divide and conquer!

About the Author

Luca Mezzalira is the VP of Architecture at DAZN with more than 15 years of experience, a Google Developer Expert on Web Technologies and the London JavaScript community Manager. He has the chance to work on cutting-edge projects for mobile, desktop, web, TVs, set-top boxes and embedded devices. Luca is currently designing the DAZN platform with his team, a sports video platform based on the cloud that enables millions of users to watch live and on-demand content. He has long experience working with Micro-Frontends, having introduced the architecture at DAZN for the web platform as well as for living room devices, which has provided a high level of flexibility, delivery speed, and independence for DAZN’s distributed teams. Luca is also the author of Front-End Reactive Architectures published by APress

In his spare time, he writes for national and international technical magazines and editors. He is also a technical reviewer for APress, Packt Publishing, Manning Publications, Pragmatic Bookshelf and O’Reilly Media.

Luca was speaker and/or keynote speaker at: O’Reilly media webinars, O’Reilly Software Architecture (New York, San Francisco and London), O’Reilly Fluent (San Jose), O’Reilly Oscon (London), AWS Re:Invent (Las Vegas), QCon (London), SDD (London), Google Developers Summit (Krakow), Google DevFest (London), UXDXConf (Dublin), Frontend Devs Love (Amsterdam), Voxxed Days (Belgrad), JeffConf (Milan), International Javascript Conference (Munich and London), JS Poland (Warsaw), Codecamp (Cluj), Code Europe (Wroclaw), JSDay (Verona), CybercomDev (Łódź), Jazoon Conference (Bern), JDays (Göteborg), Codemotion (Milan), FullStack Conference (London), Bitshift (Bergen), React London UserGroup (London), Scrum Gathering (Prague), Agile Cymru (Cardiff), Scotch on the rocks (Edinburgh and London), 360Max (San Francisco), PyCon (Florence), Lean Kanban Conference (London), Adobe Creative Suite CS 5.5 - Launch event (Milan), Mobile World Congress (Barcelona) and many others

1. Preface

1. The Frontend Landscape

2. Single-Page Applications

3. Isomorphic Applications

4. Static-Page Websites

5. Micro-Frontends

6. Conventions Used in This Book

7. Using Code Examples

8. O’Reilly Online Learning

9. How to Contact Us

10. Acknowledgments

2. 1. The Frontend Landscape

1. Single-Page Applications

2. Isomorphic Applications

3. Static-Page Websites

4. Micro-Frontends

5. Summary

3. 2. Micro-Frontend Architectures and Challenges

1. Micro-frontends Decisions Framework

1. Define Micro-frontends

2. Domain Driven Design with Micro-Frontends

3. How to define a bounded context

4. Micro-frontends composition

5. Routing micro-frontends

6. Micro-frontends communication

2. Micro-Frontends in Practice

3. Summary

4. A. What does the community think about micro-frontends?