Micro-frontends
Micro-frontends are small applications mostly divided by subdomain or functionality working together to deliver a larger application
Usually, projects come in different sizes and have different requirements. If your project is simple enough to have two or three pages and can be maintained by a single team, you don’t have to think about these Micro-frontends. You can just implement it with any of your chosen frameworks such as Angular, React, or Vuejs.
Micro-frontends High Level
Imagine a website where customers can order food for delivery. On the surface, it’s a fairly simple concept.
- There should be a landing page where customers can browse and search for restaurants. The restaurants should be searchable and filterable by any number of attributes including price, cuisine, or what a customer has ordered previously
- Each restaurant needs its own page that shows its menu items and allows a customer to choose what they want to eat, with discounts, meal deals, and special requests
- Customers should have a profile page where they can see their order history, track delivery, and customize their payment options
Type caption for image (optional)
Type caption for image (optional)
Given the fairly loose definition above, there are many approaches that could reasonably be called micro frontends. In this section, we’ll show some examples and discuss their tradeoffs. There is a fairly natural architecture that emerges across all of the approaches — generally, there is a micro frontend for each page in the application, and there is a single container application, which:
- renders common page elements such as headers and footers
- addresses cross-cutting concerns like authentication and navigation
- brings the various micro frontends together onto the page, and tells each micro frontend when and where to render itself
Server side composition
This is a fairly standard server-side composition. The reason we could justifiably call this micro frontend is that we’ve split up our code in such a way that each piece represents a self-contained domain concept that can be delivered by an independent team. What’s not shown here is how those various HTML files end up on the web server, but the assumption is that they each have their own deployment pipeline, which allows us to deploy changes to one page without affecting or thinking about any other page.
Type caption for image (optional)
Build-time integration using packages
One approach that we sometimes see is to publish each micro frontend as a package and have the container application include them all as library dependencies. Here is how the container’s package.json might look for our example app:
Type caption for image (optional)
We create all these packages in different repositories and package them as a different modules npm GitHub modules which can be imported together into another parent application
Type caption for image (optional)
Here are three different parts of pages coming from three different libraries or private packages hosted on github or NPM, This is build time integration as we will have a single javascript package at the end of code build and it becomes a single application like any other react app
Build Time Prod
Here are the advantages of this architecture.
- Apps are independent
Since all the apps are divided and developed separately these are independent of each other
- Apps are easier to understand
Apps are easier to understand because they are small and developed by a single team.
- Apps are easier to develop and deploy
As these apps are small in nature and developed by a single team it’s very easy to develop and deploy. We can even deploy independently. All packages get compiled at build time and we have everything as a single application bundle
- Apps development becomes faster
The whole development becomes faster and easier because of separate teams.
Build Time Cons
- Huge App and Bundle at build time
Since all the apps are added as the size of the package grows and it becomes a bigger bundle in size
- Apps are tightly coupled and lots of documentation
It’s easy to add packaged but every time before using we have to go through lots of documentation to understand the package service/module/components
- Apps are coupled with versions and you have to use the proper version of the package of the dependent module
- Now apps are coupled and we are using different versions of external packages so we have to maintain the discipline to use provided packages, breaking change in the package can become a problem for the whole app
- It is a build time so all should work
The whole process is built time so get all working all packages must work, any breaking change cab block whole development
- Validation using tests
Tests are not centralized as tests are written in different packages already, so we have to mock and validate things
Run-time integration using server-side composition
One of the simplest approaches to composing applications together in the browser is the humble iframe
Doing it using iframe is just an old way of doing it, now we have different tools which can manage that example like webpack, webpack 5 provided module federation
How it works
- In simple terms using runtime composition we just render other site components into a container or shell/main application, it is all runtime means at runtime we will download the bundle and render its component on UI
- In this example, app1.js and app2.js will be loaded at runtime from a different site from the same domain (sub-domains) and the host application will manage to render the required components from it
Type caption for image (optional)
There are many ways of doing it in a different framework using different tools example webpack federation for server-side composition in the next js application
https://webpack.js.org/concepts/module-federation/
We have a host application and we can have a different remote application, Here host application will render the remote application by downloading their required bundle at runtime, so its all runtime composition of components on the Host application
Simple Demo example
https://github.com/module-federation/module-federation-examples/tree/master/nextjs
Pros of Runtime Integration
As these apps are small in nature and developed by a single team its very easy to develop and deploy. We can even deploy independently.
Apps development becomes faster
The whole development becomes faster and easier because of separate teams and we are getting all package sin hand from different modules.
CI/CD becomes easier
Each app/package can be integrated and deployed separately and this makes the CI/CD process a lot easier. When we fix the app or introduce a new feature we don’t have to worry about the entire application since all the features are independent.
Independent Stacks and versions
We can choose our own stack for each app but this doesn’t happen so often But, we can have different versions of the same stack. For example, Some teams have the flexibility and time to introduce and test newer versions of the same stack.
No Shared Code
In large applications, we tend to share code across features but, this doesn’t scale well and introduces a lot of bugs and interdependency as the app grows bigger and bigger. This doesn’t apply to the Micro-frontends as we do not share the code unless it is a dumb component.
Can change architecture easily without touching old one
Sometimes we have to extend the old architecture but we might not have the developers to implement or extend the architecture. With the Micro frontends approach, we can develop the new feature with the latest stack and deliver independently.
Cons of Runtime Integration
No code sharing
No code sharing between services as all are packaged at runtime to be served from server side
Runtime failures
There may be runtime failure as we don’t know how other services are doing
Comments