As a frontend developer, all these years you were developing monoliths, even though you already knew it was a bad practice. You divided your code into components, used or and defined npm packages in your package.json or mounted sub git repositories into your project, yet you ended up building a monolith. It’s time to change it. require import Why is your code is a monolith? All frontend applications are a monolithic application in nature, except apps that already implemented micro frontends. The reason is if you are developing with the React library and if you have two teams both should be using the same React library and both teams should be in sync on deployments and always will be conflicting during code merges. They are not separated completely and most probably they are maintaining the same repository and have the same build system. The exit from a monolithic app is formulated as microservices. But it’s for backend! 😱 What is actually microservices? In general and the most simplistic explanation for microservices is, it is a development technique which allows developers to do independent deployments for different parts of the platform without harming other parts. The capability of independent deployment allows them to build isolated or loosely coupled services. To put this architecture on a more stable base there are some sets of rules to follow which can be summarized as follows: Each service should have only one task and it should be small. So the team who is responsible for this service should be small. About the size of the team and the project, one of the coolest explanation on the internet has been done by as below: James Lewis and Martin Fowler In our conversations with microservice practitioners, we see a range of sizes of services. The largest sizes reported follow Amazon’s notion of the (i.e. the whole team can be fed by two pizzas), meaning no more than a dozen people. On the smaller size scale we’ve seen setups where a team of half-a-dozen would support half-a-dozen services. Two Pizza Team I created a simple sketch to give a visual explanation for monolith and microservices: As you can understand from the drawing above each service in microservices is a standalone application except UI. UI is still in one piece! When all services handled by one team and while the company is scaling up, the Frontend team will start struggling and won’t be able to keep up with it and this is the bottleneck of this architecture. Additional to its bottleneck, this architecture will result in some organizational problems too. Assume that the company is growing and will adopt agile development methodologies which require small teams. On this common example, naturally, product owners will start to define the stories as frontend and backend tasks and the team will never be a real unit. It will be a shallow bubble which looks like an agile team but it will be separated deep inside. More on that managing this kind of team will be really a nail-biting duty. On each planning, there would be a question if there were enough frontend task or were there enough backend tasks in the sprint. To address all the problems described here and numerous others, a couple of years ago the has emerged and it started to gain popularity very quickly. cross-functional cross-functional cross-functional micro frontends idea The solution to the bottleneck problem in microservices: Micro Frontends 🎉 The solution is actually quite obvious, embrace the same principles which are working for backend services for many years: Divide the frontend monolith into small UI fragments. But UI is not quite similar to services, it is the interface between the end user and the product, it should be consistent and seamless. Even more, in the era of Single Page Applications, the whole application is running on the browser on the client side. They are not simple HTML files anymore, instead, they are sophisticated pieces of software reaching really complex levels. Now I feel like a definition of the micro frontend is necessary: The idea behind Micro Frontends is to think about a website or web app as which are owned by . Each team has a or it cares about and specialises in. A team is and develops its features , from database to user interface. ( ) a composition of features independent teams distinct area of business mission cross functional end-to-end micro-fontend.org From my experience so far, for many companies, it is really hard to directly adopt the architecture proposed above. Lots of others have a huge legacy burden which is nailing them down from migrating to a new architecture. For that reason a softer midway solution which is more flexible to allow easy adoption and secure migration is vital. After overviewing the architecture in more detail I will try to provide some insight into an architecture which is confirming the proposal above and allowing more flexible ways to follow. Before diving into the details, I need to build up some terminology. The overall structure and some terminology Let’s imagine we are dividing the monolithic app structure vertically through business functionalities. We will end up with several smaller applications which has the same structure with the monolithic application. But if we add a special app on top of all these small monolithic apps, users will communicate with this new app and it will compose the old monolithic UI from each small app into one. This new layer can be named as because it gets the produced UI parts from each microservice and combines into one UI for the end user and this would be the most straight forward implementation of a micro frontend 🤩 stitching layer seamless For a better understanding, I will refer to each small monolithic app as since they all are standalone apps and not microservices only, they all have UI parts and each represents an end-to-end business functionality. micro-app As it’s already known, today’s frontend ecosystem is highly versatile and can be extremely complex. So this kind of straightforward solutions will not be sufficient enough when the time comes to implement it for a real product. Problems to solve While this article was just an idea, I started a Reddit thread to discuss the idea. Thanks to the community and their responses I can list some problems to be addressed and I will try to describe them one by one. How to create a seamless and consistent UI experience when we have a totally independent standalone micro-apps ? Well, there is no silver bullet answer to this question but one of the ideas is creating a shared UI library which is a standalone itself too. By that way, all the other micro-apps will depend on that shared UI library micro-app. In that case, we just created a shared dependency and we killed the idea of standalone . micro-app micro-apps Another idea can be sharing on the :root level. The advantage of this solution would be the global configurable theme between apps. CSS custom variables Or we may simply share some SASS variables and mixins between app teams. The downside of this approach would be the repetitive implementation of UI elements and the integrity of the designs of similar elements should be checked and validated always for all the micro-apps. How do we make sure that one team is not overriding the CSS written by another team? One solution is CSS scoping via CSS selector names which are carefully selected by the micro-app name. By putting this scoping task to the will reduce the development overhead but will increase the responsibility of the . stitching layer stitching layer Another solution can be forcing each to be a . The advantage of this solution is the scoping done by the browser, but it comes with a price: it is nearly impossible to do server-side rendering with shadow DOM. Additionally, there is no 100% for custom elements yet especially if you have to support IE. micro-app custom web component browser support How should we share the global information between micro-apps? This question points out to one of the most concerned issues on this topic, but the solution is pretty easy: HTML 5 has pretty powerful functionalities which are not well known by the majority of frontend developers. For example, are one of them and it is the solution for sharing information within the micro-apps. custom events Alternatively any shared pub-sub implementation or T39 observable implementation can do the trick. If we want a more sophisticated global state handler we can implement a shared miniature Redux, by that way we can achieve more reactive architecture. If all micro-apps are standalone apps, how do we do client-side routing? This problem is up to each implementation by design. All major modern frameworks are providing powerful routing mechanisms on the client side by using browser history state. The problem is which application is responsible for the routing and when. My current pragmatic approach is creating a shared client router which is responsible only from the top level routes and the rest belongs to the respective micro-app. Let’s say we have a /content/:id route definition. The shared router will resolve /content part and the resolved route will be passed into ContentMicroApp. ContentMicroApp is a standalone server and it will be called with /:id only. We must have the server-side rendering for sure but is it possible with micro-frontends? Server-side rendering is a tricky problem. If you are considering iframes to stitch the then forget about server-side rendering. Similarly, web components for stitching task are not powerful than iframes. But if each is able to render its content on the server side then the will be responsible only for concatenating the HTML fragments on the server side. micro-apps micro-app stitching layer Integration with a legacy environment is vital! But how? To integrate a legacy system, I would like to describe the strategy of my own that I named as “ ”. gradual invasion First, we have to implement the stitching layer and it should have a functionality of transparent proxy. Then we can define the legacy system as a by declaring a wildcard route to it: . So all the traffic will hit the stitching layer and will be proxied to the legacy system transparently since we don’t have any other micro-apps yet. micro-app LegacyMicroApp Next step will be our first movement: We will take a small bite from the by deleting the main navigation and replacing it with a dependency. This dependency will be a implemented with a shiny new technology: . gradual invasion LegacyMicroApp micro-app NavigationMicroApp Now the stitching layer will resolve each route as and it will resolve the dependency as and serve them by concatenating these two. LegacyMicroApp NavigationMicroApp Then the next bite will come for the footer by following the same pattern with the main navigation. And then we will continue taking similar small bites from until nothing left from it. LegacyMicroApp How to orchestrate the client side so we won’t need to reload the page each time? Well, the solves the problems on the server side but not on the client side. On the client side, after loading already glued fragments as a seamless HTML, we don’t need to load all the parts each time on URL change. Therefore we have to have some mechanism which loads fragments asynchronously. But the problem is, these fragments may have some dependencies and these dependencies need to be resolved on the client-side. That means a micro frontend solution should provide a mechanism to load and also some mechanism for dependency injection. stitching layer micro-apps According to the questions and possible solutions above, I can summarize everything under the following topics: Client-side Orchestration Routing Isolation of micro-apps App to app communication Consistency between micro-app UIs Server-side Server-side rendering Routing Dependency management A flexible and powerful yet simple architecture So, it worthed the wait all along this article! The basic elements and requirements of a micro frontends architecture finally started to reveal itself! With the guidance of these requirements and concerns, I started to develop a solution which I named as . 😎 Here I will describe the architectural goal of this project by underlining its main components in an abstract manner. microfe It is easy to start with client-side and it has three separate backbone-structures: , , and one extra AppsManager Loader Router MicroAppStore. AppsManager AppsManager is the core of client-side micro-app orchestration. The main functionality of AppsManager is to create the dependency tree. When all of the dependencies of a micro-app are resolved, it instantiates the micro-app. Loader Another important part of client-side micro-app orchestration is the Loader. The responsibility of the loader is fetching the unresolved micro-apps from the server-side. Router To solve client-side routing I introduced the Router into . Unlike the common client-side routers, the router has limited functionalities, It does not resolve the pages but micro-apps. Let’s say we have an URL /content/detail/13 and a . In that case, the router will resolve the URL up to /content/* and it will call /detail/13 URL part. microfe microfe ContentMicroApp microfe ContentMicroApp MicroAppStore To solve micro-app to micro-app client-side communication I introduced MicroAppStore into It has the similar functionalities of Redux library with a difference: It is resilient to asynchronous data structure changes and reducer declarations. microfe. The server-side part can be a little bit more complicated in implementation but simpler in structure. It consists of only two main part and lots of . StitchingServer MicroAppServer MicroAppServer Bare minimum functionality of a can be summarized as and . MicroAppServer init serve While a booting up first thing it should do is calling register endpoint with a which defines the micro-app , , and of . I think there is no need to mention about serve functionality since there is nothing special about it. MicroAppServer SticthingServer micro-app declaration dependencies type URL schema MicroAppServer StitchingServer provides a endpoint for When a registers itself to , records the declaration of the StitchingServer register MicroAppServers. MicroAppServer StichingServer StichingServer MicroAppServer. Later the uses the declaration to resolve the from the requested URL. StitchingServer MicroAppServers After resolving a and all of its dependencies, all relative paths in CSS, JS and HTML will be prefixed with related public URL. One additional step is prefixing the CSS selectors with a unique identifier of to prevent collision between micro-apps on client-side. MicroAppServer MicroAppServer MicroAppServer Then the main responsibility of comes into the scene: composing and returning a seamless HTML page from all collected parts. StitchingServer A Glimpse of Other Implementations out There Even before it was called micro frontends by 2016, lots of big companies were trying to solve similar problems such as Facebook with its . Nowadays the idea is gaining momentum. The companies with different sizes are interested in the subject and investing time and money on it. For instance, open-sourced its solution which is called . I can say that and Project Mosaic are following similar approaches with some vital differences. While microfe embraces full decentralized route definitions to empower more independence for each micro-app, Project Mosaic prefers centralized route definition and layout definitions for each route. By that way, Project Mosaic allows easy A/B testing and dynamic Layout generation on the fly. BigPipe Zalando Project Mosaic microfe There are some other approaches to the subject such as using iframes as stitching layer which is obviously not on the server-side but on the client-side. This is a very simple solution which does not require so much server structure and DevOps involvement. The job can be done by the frontend team only, so it creates a less organizational burden on the company and also it is less costly. There is a framework already out there called . The project relies on naming conventions of each app to resolve and load . Easy to grasp the idea and follow the patterns. So it can be a good initial introduction for experimenting the idea on your own local environment. But the downside of the project is you have to build each in a specific way so they can play nice with the framework. single-spa micro-apps micro-app Final Thoughts I believe that micro frontends topic will be discussed more frequently in time. If the topic manages to get the attention of more and more companies, it will be the defacto way of development in large teams. It can be really beneficial in the close future for any frontend developer to grasp some insights and experience on this architecture. Consider contributing I’m heavily experimenting on micro frontends with a noble goal in my mind: Creating a micro frontend framework which can solve the majority of problems without compromising of the performance and ease of development and testability. If you have any bright ideas to show, do not hesitate to visit my repositories, open an issue or reach me out via comments below or . I will be there to help you! 🙂 Twitter DM _micro fe app registry server. Contribute to onerzafer/micro-fe-registry development by creating an account on GitHub._github.com onerzafer/micro-fe-registry _a micro front end infrastructure. Contribute to onerzafer/micro-fe development by creating an account on GitHub._github.com onerzafer/micro-fe
Share Your Thoughts