Micro Frontend

Mar 16, 2022by, Abil Manoj

Uncategorized

Conventionally, we always followed a monolithic approach when it comes to frontend development. When the backend dev team were given the privilege(or option) to write backend controllers as microservices with each service can be written in any language as demanded by the task that it was expected to perform, the frontend always had to build upon a single basement.

But what if I say we can bring the beauty of writing microservices in the backend over to our frontend.

Say hello to Micro Frontend.

This is not a brand new approach. It’s been a while since it’s been around us. But the adoption rate was minimal since there was not a proper framework that could be easily used by development teams to pull this off in their project.

Wait wait… Before going too technical on this, let me just give a quick theory on who this “superman” is.

Micro Frontend is a method by which a frontend development team is given the “freedom” to focus only on their work, and need not bother much about what other teams working in his similar level are doing. This gives them the independence to develop using their preferred frontend stack (React,Vue,Angular etc..), develop components the way they wish etc.. This is basically an architectural design pattern. For the end user, the application is presented as a regular Single Page App(SPA).

Benefits of Micro Frontend approach:

  • Faster Builds – The bigger the application is, the longer it takes time to get built. Nowadays, build tools like webpack are improving the build speeds by doing the process using multiple threads, but that is not actually sufficient. In this context, developing a large app by breaking it down into smaller chunks and developing and building these chunks independently saves a hell lot of time. These different build files can be later integrated together to get the bigger picture( the final version of the app).
  • Dynamic Deployment – This is one of the main highlights of this approach. A feature can be developed independently for an application and can be implemented to the app without the need to recompile the entire application.
  • Parallelism Development – Each team is independent to work on their assigned feature without much of an interaction between other teams. They have the flexibility to choose the tech stack they feel comfortable, to implement practices they feel is best. In general, it helps to add a lot of flexibility to the project. However these independent subprojects need to be tangled to the main project making use of some public API.

Implementation:

  • Routing apps – Typically, the websites that we see everyday come with a URL that represents the application state of that SPA(Single Page Application) page. But this approach is a bit complex when it comes to micro frontend since each micro app which builds up the whole app needs to update its state according to the URL provided.  The way to solve this is encoding each micro app’s state into the single composite URL and using a small macro app router to combine these different encoded URLs as well as decode information from them. This will also require logic in each micro app to update its state by looking into the URL and to also update the URL itself according to its state change.

  • Loading apps – In the case of a regular SPA webpage, each route will have their import statement. In the case of micro frontend, having this kind of an implementation could mean we need to define routes for every app/feature component. This could be a daunting task and affect the scalability of this approach. So an alternative is to create an instance for each component at runtime by listening to the URL.

onRouteChangeHandle (route) {
// Assuming routes are “/<app_name>/<internal-app-url>”.
let parts = route.split(‘/’);
let app = parts[1];
let app_url = parts.slice(2).join(‘/’);

if (this.isRunningApp()) {
this.suspendCurrentApp();
}
import(`/${app}/main.js`).then(app => {
this.startApp(app, app_url);
});

In the above example, the runtime is looking at the first part of the URL which most likely maps the to a folder in the system that holds the code of the app. Since the app could already be running,  we suspend the app first and then load the code from the folder. Once loaded we start to pass the rest of the URL.

  • App Lifecycle – Apps can be started, suspended, resumed and exited as part of managing system resources. 

class MyApp extends Application {
constructor (args) {}
onAppSuspended () {}
onAppResumed () {}
onAppQuit () {}
}

  • Communication between apps – for simple data transfer, the URL is enough. The team developing the feature/app can be asked to develop a public URL API which they could guarantee backward compatibility for it. This is a similar approach to how apps communicate in an OS like Android. The OS intercepts these URL’s and loads the app passing in the data. This principle can be implemented in micro frontends as well.The runtime will intercept the URL, load the app and pass the rest of the URL data into the app.

But there can be instances where you need to pass highly complex data. One approach to solve this is to store a blob of data into a server and use a temporary ID in the URL which an app can use to query the blob of data. This is more complicated and requires careful management of data in the server, but it offers more benefits other than just storing data in the server.

Conclusion:

Micro frontends are not a solution for all projects and all development. For most of the cases code splitting and fragmentation of components is more than enough. This approach is best suited for larger organizations with a large number of teams working on a project. So in order to overcome the hurdle of communication between these large numbers of team players, an independent,stand-alone micro frontend approach can be used to reduce the pain of communication when it comes to frontend development.