Kavindu Vindika – Intern Software Engineering
Before we get started,
Frontend development should be done with assurance from the product owner, for the features that it renders. If the features don’t fit the product owner’s ideology or if more features need to be added, the development team should be able to do the necessary changes with minimal effect to the application. Each team member should have deep knowledge about the monolithic code-base that they are working on in order to render any changes that they make, without breaking the application.
Scaling frontend development where many teams can simultaneously work on a large and complicated project is on the list of the impossible and hard to achieve. Pressurized by the product owner for changes within a deadline, and the confusion of the team members regarding the hard to understand monolithic code-base leads to desperation and frustration with time wasted for the clarification.
Now, lets get started
Then think about how monolithic backend breaks down into manageable pieces, namely micro-services, similar to the frontend. This is achieved with micro-frontend architecture increasing the effectiveness and efficiency of the teams working on frontend code. As the name suggests frontend will be broken down into pieces, where each team works independently to render the features.
The key benefits are smaller and more understandable codebases, increased scalability with independently working teams, and ease and efficiency of rendering updates and changes to the application.
Micro-frontend architecture comes with single page applications, where features in a particular page can be divided into micro frontends in order to allocate them between autonomous teams. Each feature component will be independently rendered to the DOM and doesn’t have any effect on other features. Due to the decoupling between features, it allows each team to work on their allocated task without having any communication or clarification from the other teams to follow their procedure.
When do we use this?
You shouldn’t use micro-frontends simply because it seems to be a cool feature! Feature selection should be done on scalability and the complexity. If the feature seems to be divisible into sub-domains, then work on that particular feature as a separate micro-frontend. This provides you with ease in managing your codebase without the pain of dealing with a single monolithic-codebase.
A Corporate World Example…
The use case: a project where an application is a web portal through where we can access more than one application.
To clarify, I’ll list down the code-bases that my team worked on (each represents a micro-frontend)
- Web Portal — act as the gateway or portal to access the other applications.
- Dashboard — one of the applications accessible via sub-domains of the SPA.
- Payment application — one of the applications accessible via sub-domains of the SPA.
Following github repositories will be helpful to shed some light when you’re moving with parcel configuration.
For that, first clone the repos and do the following
npm install and npm start
In my opinion, the best way of achieving the benefits from micro-frontends would be to have each vertical team working on the end-to-end flow of the relevant micro-frontend. This means, not just the frontend, but also the backend connectivity for providing micro-services.
As a result, each team will have the knowledge and accessibility to make changes to the relevant frontends, BFF(backend-for-frontend) or backends, without any effect on other teams’ procedures.
Therefore we had the following application architecture, to provide each team to work on their on codebases independently.
How single-SPA comes into the picture…
Go through the documentation to guide you through the next section.
With single-SPA, only one application has the index.html which is the DOM where we render all our components. In this example, the web portal contains the index.html file and it renders other applications with the sub-domain routine.
In order to do that, each application should be configured and registered in a single-spa config file to let it initiate, load, mount and unmount.
registerApplication(name, loadingFunction, activityFunction)
To call registerApplication api, you have to define the loadingFunction to import the bundle.js file for the relevant application and activityFunction, where the application mounts whenever routed to the given path.
I won’t be discussing the implementation, since it’s already provided with the documentation and github repository.
Now let’s move onto the most important topic, How and Why in Parcel Configuration.
What we wanted to achieve from the single-spa was feature separation to work independently. But what if some data should be passed from the main feature to the other features? That would result in some sort of coupling between the features, but it isn’t avoidable if the data has to be passed.
To do this, default props can be passed down to each application with registerApplication api. However, once the application is bootstrapped and mounted, the props passed can’t be changed, even if the passing props data can be changed in the main feature. That’s because with registerApplication api, it isn’t possible to provide a life cycle method to each application to update itself with the changes in the props.
In the example, we have 2 applications (dashboard and payment) that are registered as single SPA applications in a web portal. Since we are going to have user input in the web portal and pass it down to these 2 applications, we need to have a way to update the props, rather than having a way to pass default props like in the registerApplication API. For that parcel configuration is necessary. With Parel Configuration we can give the updated life cycle method to each application, specifically, in the web portal there is no need to provide a separate single-spa-config file to start the registered applications.
Each application can be mounted to the DOM as a normal component with the required props provided in web portal as follows.
As you can see, we can mount our application as a react component with the help of single-SPA parcel. As a result we can pass the props just like a normal react component.
Here, the component to get the user input is mounted using the web portal, and each button for the dashboard and payment application redirects to the relevant application. Since we are using Parcel component to mount each application, the updated props will be instantly visible to each application.
In the dashboard and payment application, I added the following component to view the user input.
However, other than the most essential props, any other data should not be passed from the web portal to the micro frontends, to keep the loose coupling.