How FloQast Is Scaling Our Micro-Frontend Architecture
Jul 19, 2021 | By J.C. Yamokoski
Almost one year ago we described how FloQast was working to dismantle our front-end monolith in favor of independent micro-frontends built with React. And I'd like to take a second to say: "Yay, us! We did it!"
I can proudly say that our client-facing web app is now a full aggregate of decoupled micro-apps composed together at runtime to behave as a single unit. It was a major multi-team effort, and the end result was a huge success!
By allowing any particular feature of the app to be isolated into a dedicated micro-app owned by a single responsible team with its own unique deployment pipeline, this architecture is helping to drive our goal of enabling small, focused teams to iterate quickly and independently.
And, to top it all off, by leveraging our internal GRAIL project, we're able to spin up a brand new micro-frontend within a matter of minutes via a single Slack command!
But, will it scale?
In this previous post, we gave some specific examples, including working code sandboxes, of how we were building out the client hub and micro-frontends.
The crux of it all is a
MicroClient component, which accepts a URL pointing to the JS/CSS bundle, wrapped in a
ReactRouter. Whenever a defined route is hit, the
MicroClient fetches the appropriate bundle and loads the client.
This approach worked very well. But at the time we only had a few micro-frontends and we wanted to scale that up significantly.
But, there was one major problem. The pattern involved extracting a client from the monolith and injecting it right back in. Meaning the monolith was acting as both a client and the hub.
That would not scale well, so we decided to re-evaluate and see if we could do better.
No need to re-invent the wheel
The reason it wouldn't scale was twofold:
- There were multiple responsibilities, and therefore, multiple different teams all working within the same repo. The monolith itself was controlled by one team, while each separate client was controlled by others. This resulted in a constant barrage of merge conflicts and release queue backups; which would only be exacerbated by continuing to break out more clients.
MicroClientcomponent was entirely homegrown. Meaning any bug fixes or new features would entirely fall on us to implement. Building a micro-frontend architecture is cool and all, but that's not our bread and butter. We should be focusing on what makes us unique.
Ultimately, we decided to leverage an existing framework, single-spa, which is an open-source, incredibly well-documented framework for creating front-end microservices. Jackpot 💰
We were able to spin up a brand new client-hub built with single-spa, integrate all of our existing clients, and finally remove all of the hub responsibilities from the monolith.
Here are some of the more notable improvements this provides over our previous setup:
- While we have a team responsible for maintaining the hub, they don't need to worry about the underlying micro-frontend code specifically, saving time to focus on other projects.
- More control over the loading/unloading of clients. Previously we could only load clients; i.e. once it was mounted it persisted until a full reload; whereas now navigating away from a mounted client automatically unmounts it, freeing up precious browser resources.
- single-spa is built upon import maps and SystemJS which opens the door to some seriously lean local development.
Try it yourself
If you're interested in learning more, the single-spa devs have put together an interactive playground that allows you to fully test out the framework. Highly recommended!
There is also a CLI for generating all necessary aspects of a micro-frontend application; which makes bootstrapping from scratch a cinch.
With the groundwork now complete, we have a solid foundation of microservices on both the back-end and front-end on which to build a world-class application with our high-performance teams! Stay tuned to see what we come up with next. The future is looking bright 😎