A couple years ago, microfrontends (MFEs) were introduced to Open edX: the goal at the time (and now, still) was to migrate all major features from the LMS and the Studio to dedicated, standalone bundles of static assets. In a nutshell, MFEs were the “future” of Open edX development.
(There’s certainly a lot more to be said about the history of MFEs but I’m definitely not the most informed person on that topic)
Today, the Open edX releases ship with multiple MFEs enabled by default (profile, learning, account, gradebook). We (the community) have a lot of experience developing and deploying MFEs. Generally speaking, when we talk about new features we try to architect them as new MFEs. So I thought it would make sense to take a look back and consider where we stand, what the adoption of MFEs has brought us, what problems we are facing and how we can address them. Basically, I want to start a conversation to ask people how they feel about MFEs.
I’ll start with my own impressions, but I must acknowledge that they are very incomplete; for instance, I personally have zero experience creating MFEs from scratch or adding new features to existing MFEs. I’m mostly tasked with the deployment of MFEs (via Tutor, of course) and fixing minor issues.
Building on config change is costly
MFEs are bundles of frontend-only html/css/js code. Thus, they need to know about platform configuration (NODE_ENV, BASE_URL, etc.) at build-time. This means that:
- the build process must be run every single time that a configuration value is modified.
- we cannot provide plug-n-play Docker images to be run by all users.
- people deploying to Kubernetes must also setup a Docker image build factory.
For instance, in the context of Tutor, re-building MFE images might take 10 minutes or so. What is worrying me is that this time will increase linearly as we add new MFEs, and that all users must pay this cost for every configuration change. Configuration changes happen frequently, because users must upgrade their platforms, customize stuff, play with plugins, switch from one environment to the next, etc.
If we are to multiply the number of MFEs out there, then we must definitely find a solution to this problem.
Building is not a uniform process
The way that the final MFE image is built in Tutor is that we have single template for every app: tutor-mfe/Dockerfile at e99e844920bb6c0be597d52947b46c7b433cd8f7 · overhangio/tutor-mfe · GitHub
It basically goes like this:
git clone ...
npm install
npm run build
Then all static assets are gathered in one place and served by a single web server.
The simplicity of this build/deploy process is one the great things about MFEs. But we have a problem when one of the MFEs needs to be deployed in a different way. This happens, for instance, when:
a. a manual patch needs to applied (a security patch for instance)
b. some dependency needs to be upgraded (such as frontend-build)
c. they depend on older requirements (webpack for instance) for which the process must be slightly different
Some of these issues are due to how Tutor implements MFEs, but honestly I cannot figure out a way to proceed that would be both robust and easy to understand for end users. Some further reflection would be needed, I guess.
Static assets are too large
From the final user perspective, accessing an MFE requires downloading a couple megabytes worth of static assets, and these assets are different for every MFE. For instance, the js and css assets from the account MFE weight ~2.7 MB. It’s possible to cache assets from one call to the next, but not across MFEs.
Again, if we are to scale the number of different MFEs, we need to figure out a way to avoid downloading heavy assets from one page to the next.