Lerna & Module Federation for AWS micro-frontends
This article concludes my mini-series dedicated to a complete AWS architecture for Module-federated micro-frontends. The first two parts consisted on below subjects.
- A high level AWS architecture introduction
- A CDK implementation
This final part will show how this Javascript application was implemented by using:
- Lerna, a JS tool to manage multi-package repositories by using YARN/NPM and Git.
- Webpack’s Module Federation plugin, to expose micro-frontends as remote scripts.
I recommend to have a look at this Github repo, which presents a wide list of implementations to see the plugin in action. For this app, I leveraged the dynamic host system host example.
MonoRepo setup
Our mono-repo contains all micro-frontends and their IaC in a single place, as shown below.
The repository consists of different parts:
- React Micro-frontends (mfe-apps) folders containing their independent implementation. One of them (mfe-app1 or parent) is the application shell orchestrating the other two micro-frontends (here also called child apps).
- A cdk folder including IaC components presented in second article.
- Lerna and package json files for micro-frontends’ dependencies and bootstrap.
The app will result in below.
Lerna
Lerna helps organizing mono-repo as workspaces where you define apps into packages. First you should initialize your project by running below commands:
npm i lerna -g
npx lerna init
This will generate a lerna.json and a package.json.
- In package.json you would fill typical dev and prod dependencies along with scripts such as:
“start”: “lerna run — scope @dynamic-system-host/* — parallel start”
Above command finds all packages whose name (aka scope) starts by “@dynamic-system-host” (later under Child Apps section).
- In lerna.json you will specify type of npmClient used (either npm or yarn) and delegation to package structure to yarn by Yarn’s useWorkspaces.
The Child apps
The micro-frontends are very simple web app based on React and Webpack. You can check one example in below link.
There are only two peculiar features to mention in regards of Child apps.
Package name
By defining the package.json name field, you will instruct Lerna on what package to start (remember the scope parameter of the npm run start script).
Webpack Configuration
Module Federation plugin exposes the mfe-app2 micro-frontend to a remoteEntry.js which will bootstrap the App.js file as main entry point of the module.
It also allows to share libraries across micro-frontends. Typical case is that in a micro-frontend app, you would not want to load the framework specific libraries (e.g: React and React-dom) every time, but reuse it or being smart about it.
Below shows an extract of the webpack file for one of the child apps.
The App shell
The app shell serves as container for the other micro-frontends, but how does Module Federation literally make this happen? Micro-frontends can be defined as Systems:
Let’s look at them.
Script injection
When micro-frontends are rendered, a dynamic script gets simply injected in the HEAD tag of the page, via the useDynamicScript function. This script is the remoteEntry.js code generated by the Module Federation plugin, which allows us to load the micro-frontend.
React Lazy-loading and Suspence
The micro-frontend is loaded as a lazy component via the React.lazy. This renders a dynamic import as a regular component, supporting code-splitting. It requires a Promise which has to resolve to a Module being retrieved from a datasource or, in this case, the global window object.
Once retrieved, it will be initialized via the below loadComponent function and loaded via React.Suspence.
Mounting Systems
Systems are mounted by providing three properties:
- A remote url, the remoteEntry url script exposed by Module Federation
- A scope - micro-frontend identifier
- A module, the entry module to be loaded
Abstracting micro-frontends as Systems allow better module federation definition and easier mounting strategy:
Conclusion
This article concludes my quest to try to demonize the Module Federation plugin and the complexity behind adopting module federated micro-frontends, and see how feasible and scalable is to deploy and host them on AWS Cloud.
It just touches the surface and I acknowledge the many challenges that adopting micro-frontends entail (trust me!), but I hope it makes you embracing this architectural style and trying out of it fits your organization. Hope you enjoyed this mini ride :-)