How to build a Vue-based micro-frontends infrastructure
For the past few years as a tech lead consultant at Tikal knowledge, I’ve encountered several companies and startups struggling with tech debts, the need for migrations and refactors, and existing design patterns that were good for the bootstrap of those applications, but made complicated and hard to work with when applications grew.
A micro-frontend infrastructure can help you regardless of whether your application is built with a single framework or you want to replace the framework.
Micro-frontends with iframes have cons
- Development cycle: If you don’t have a well-written infrastructure, you will have some issues with things like the HMR, running local environments, running a QA environment, and the CI process.
- Shared state: Managing state when you have iframe needs some infrastructure, to know if a certain data is needed across iframes, or between child-frame and a parent-host.
- Routing: Sharing routes and permissions between the host application and its children, or among the children is difficult.
- Load time: When not done right, the loading time of iframes can be quite slow, and there are probably duplicate libraries across iframes.
- Confidence: Running an operation from one frame to the host or another frame needs to have some level of abstraction, and you don’t always have the “confidence” that the operation you wanted to run is running or will run in another context.
The advantages of micro-frontends with iframes
Yes, there are some cons, but there are some significant benefits too.
- Once your infra is complete, your development cycle can be amazing!
Working with HMR, different versions of the same framework / another framework, managing stupid-simple state for a micro-app instead of a bloated gigantic state of a huge app, you can have dynamic environments and replace small pieces of your app without deploying everything, and test several pieces from different versions together. - Once your infra is complete, routing isn’t a problem at all.
You can merge routes from different applications, dynamically, and it can work great. - With CDN caching, shared resources, and memory cleanup when an iframe dies, loading times can improve.
- Security-first: Iframes force you to build more secure applications since some data needs domain validation and sharing information about the user may require them to run under the same domain.
- Complete isolation: The isolation of iframes makes it easier to make sure that the CSS of one app will not affect other apps, and it makes it easier to manage isolated small scopes of state and translation files (i18n).
- Separated processes: The browser creates a completely separate process for iframe scope, so you can feel safer if an internal stack overflow of a micro-application will not affect the behavior of the host-application, and vice-versa.
The missing piece of micro-frontends infrastructure
The most important piece inside a platform that uses a micro-frontend solution, is a micro-frontend infrastructure.
Writing this infrastructure is not an easy task, but I believe it should become common knowledge that will share common behaviors of micro-frontends solutions.
That's why I started creating microf.
What is @microf/* ?
When I started to create this repository, I thought about a plugin that will implement the best development experience I wanted to have for my projects, and I wanted it to work with zero configuration.
I first started to implement it with Vue 3, and then I realized that the proper way is to create a unique plugin per framework and position.
Right now, this repository includes:
@microf/vue-host — the plugin for a host application written in Vue 3.
@microf/vue-child — a plugin for a child application written in Vue 3.
The assumptions of the plugins
To create the leanest plugin, I needed to have some basic assumptions:
You’re using Vue 3.
You’re using Vue-router.
Assuming those libraries, I can be sure that I don’t need to implement my abstraction over location changes, and that I can use Vue-router’s guards to trace routes changes.
I can also elaborate <roter-view> and <router-link> components, and I don’t need to implement things that have already been implemented.
Now, let’s demonstrate the flow of the plugin:
Host application initial load:
The plugin requests the routes of all micro applications and extends the host router’s routes.
The host is routed to an internal route of a micro-app:
An internal route change happens at the child application:
Host routed to an existing micro-app route:
In that case, the host application is routed into a child application route that already exists on the screen as part of a child application.
In that case, location change to the iframe will apply a full refresh to the micro-application, which is not ideal.
It is solved by the plugin inside the host application sending the message of the route change to the plugin inside the child application, which manages the change using internal Vue-Router’s methods instead of changing the location itself.
— — — — — — — — — -