What are Microfrontends?
Coming from a microservices background, the first time I heard the term ‘Micro-frontend’, I was left scratching my head. I understood what microservices were, and how they interacted with each other via various protocols (sync/async) or via message brokers. But what could micro frontends be, and how would micro frontend applications interact with each other? Can they be technology agnostic like in the case of good old microservices? What would be the challenges of breaking a monolith UI application into a micro frontend architecture? How to implement micro frontends from a coding perspective? It took me a while to get my head around these questions. Through this article, I will try to summarize and share my learnings.
?What are Micro-frontends?
Micro-frontend application is basically one UI application containing sections or having routes that are pages of another application. Just like micro-services do it for the backend, micro-frontends break the traditional monolith frontend application into separate applications based on respective features. These separate applications are maintained as separate code repositories and can be worked upon by different engineering teams. Micro-frontends are technology agnostic, eg. one application may be written in React, and the other in Angular, and they will still come together to be part of the main application hosting these micro-frontends.
The micro-frontend architecture consists of one?Container/Host?application and one or more?Remote?applications:
The container application is the main application that integrates with different remote applications to render different sections of the website. Note that these micro-frontends (remotes) do not have any direct communication with each other, and each integrates with the container application directly. There should be no coupling or sharing of state between the applications.
There are 3 types of micro-frontend integrations:
Out of all the above, option 2 above is the most effective and flexible option for implementing true micro-frontends, and that is what we are going to cover in this article. To achieve runtime micro-frontend integration, the easiest and the more traditional approach is to use iFrames in the container app. But iFrames come with many issues: isolated (can’t share any dependency or a feature), poor performance, and difficult to get a good UX.
The better and more modern way to achieve runtime micro-frontend integration is by using the plugins approach.
Webpack provides WebpackFederationModule?that helps implement micro-frontend applications.
领英推荐
Some challenges when using micro frontends:
2.1 Use css-in-js library, which generates random CSS tags per usage. Read more about it here:?https://medium.com/jobsity/css-in-javascript-with-jss-and-react-54cdd2720222
2.2 When using a framework like Angular/Vue, use the framework’s component style scoping.
2.3 Namespace all your CSS. Ie in CSS file give as: .remote1 .h1 {…}, and in the container HTML use the remote as <div class=”remote1”><h1>……</h1></div>. But now care has to be taken by developers to namespace all CSS in the remote app, and also this is kind of creating a kind of coupling between the remote and container app, hence not a preferred solution.
3. Authentication: How to manage the logged-in user’s information across various applications? The best implementation is for the container app to maintain user AuthN details, and pass them down to all remote apps as and when they are routed to. The webpage for authentication can be a separate remote application as well, but that would only be for the HMTL rendering of the authentication page, and not for managing the authentication centrally.
4. Path routing:?Maintaining a history of routes when migrating from a page of the container app to page(s) of the remote app. There are many ways to implement this routing. The easiest way is for the routes in a container to point to the remote app, and the routes in the remote app to point to specific pages of the remote app. To maintain the history of pages visited, use 'Browser History' in the container application, and ‘Memory History’ in all remote applications. You will need to sync these histories between applications. Ie, if a route is navigated in the container app, we need to communicate that to remote apps to update their respective memory histories, and likewise, if a route is navigated wrt a remote app, then the same needs to be communicated to the parent app to update its browser history.?This communication is usually done using callbacks.?
Refer to this link for more understanding of browser history vs memory history.??
Concluding the article with a GitHub POC URL, where we run 3 different micro-frontend apps: 1 container and 2 remotes. Check the webpack.config.js of each application, on how different files from remote apps are exported, and then imported into the container app.