How to build a dynamic micro-frontend architecture in React?

First of all, what is this Micro-frontend thing?

Alright, let’s get into it – Micro-Frontend Architecture, a game-changer in web development. Say goodbye to those bulky monolithic structures we’re all tired of. Micro-Frontend Architecture breaks down the frontend into smaller, more manageable chunks. It’s like breaking a big rock into smaller stones – easier to handle, right?

With micro-frontends, teams can work independently on different parts of the frontend. No more wrestling with massive codebases that feel like a maze. This setup is all about scalability, maintainability, and efficiency, especially as web applications get more complex.

But here’s the kicker – micro-frontends mean faster release cycles. You can update specific parts without risking the entire app. It’s like fixing a broken window without renovating the whole house – a practical approach.

And here’s the deal – teamwork is key. Each team can focus on their part of the frontend, collaborating more effectively. It’s like having your own projects within the big project.

How is the Micro-frontend architecture composed?

Let’s break down this Micro-Frontend Architecture into two main parts.

building

First up, we’ve got the main portal – think of it like the central hub where everything comes together. This portal takes care of the big picture stuff, like managing user authentication, permissions, and navigation. It’s like the front door of a building – you walk through here to get where you need to go.

Then, we’ve got all the micro-frontends – these are like the specialized departments in the building. Each micro-frontend handles specific business features, like a sales department or a customer support team. They’re small, focused, and they get the job done efficiently.

Together, the main portal and the micro-frontends create a dynamic and flexible architecture that’s perfect for modern web applications. It’s like having a well-oiled machine – everything works together seamlessly to deliver an awesome user experience.

Why should the micro-frontends be dynamically loaded?

While it’s true that micro-frontends are often statically loaded, meaning they’re all loaded upfront regardless of user permissions, there’s a better way to go about it. Imagine if you only had to carry what you needed instead of lugging around everything all the time.

That’s where dynamic loading comes in. By loading micro-frontends based on the user’s permissions, we can keep things lighter and safer. This means only loading what each user actually needs, reducing the app’s footprint and preventing security breaches. It’s like giving each person just the keys to the rooms they’re allowed in – simple, efficient, and secure.

How can this be achieved?

Alright, so we’ve talked about how loading micro-frontends dynamically is the way to go. Now, let’s dive into how it’s actually done. It all starts with a call to an API – think of it like placing an order at your favorite restaurant, but instead of food, we’re asking for micro-frontends!

This API is like the gatekeeper, and it knows exactly what micro-frontends each user is allowed to access. So, when a user makes a call to the API, it tailors the list of micro-frontends to load based on that user’s permissions. It’s like having a personalized menu just for you. This way, users only get what they’re supposed to, keeping things efficient and secure. And that’s the beauty of dynamic loading – it puts the power in the user’s hands, ensuring they get the experience they deserve.

Do you have a working example?

Sure! I wouldn’t be presenting this architecture without testing it upfront. So, I created a small POC application that showcases the architecture presented here.

You can find it at this address .

There you’ll see that the project is built using a monorepo. This is by no mean a necessity for building such architecture, but it was easier during the conception phase to be able to work on different pieces that needs to fit together at the same time. Once you’ve put such architecture in place, you are free to work on completely separated repositories for each piece of this giant puzzle.

Also note that, while the micro-frontend approach is supposed to be technology agnostic; i.e. each micro-frontend can use a different web technology or framework, this POC uses React for all parts of the application. You can reuse this way of working to integrate other technologies or frameworks if you need to.

The project has different parts:

  • The Portal (/apps/portal): This is the keystone of this architecture, the central hub as we explained it earlier. In this project you can find that

  • If the user is not yet logged in, the login page is displayed,

  • Once logged in, the API is called from the Portal.tsx component to get the list of Micro-frontends the logged in user has access to. This is where the dynamic specificity of this architecture is put into motion.

  • For each micro-frontend received from the API, the portal will create a MicroFrontend.tsx component. This component is responsible to get the manifest.json file from the url of the micro-frontend (cache it to increase future performance). With the content of the manifest file, it can render an AsyncComponent.

  • The AsyncComponent.tsx is responsible to load the corresponding js (and possibly css) files that are defined in the manifest.json file. As a convention, the micro-frontends will “register” themselves on the custom window.microFrontends object. This loading logic is externalised in the ModuleService.ts file.

  • The Server (/apps/server): This naive implementation of a server is done using express. It is only for demonstrating purpose. It assumes that the logged in user is passed in the Authorization header and trust it. This is by no mean how it should be implemented in the real world but was an easy hack for this purpose.

  • The MFEs (/apps/mfe1 and /apps/mfe2): Those are 2 very simple React application that are bundled in a way to be loaded by the portal:

    • They register themselves in the customwindow.microFrontends object in the index.tsx file. The actual entry point for those modules is their Module.tsx file.
    • They are built using a common webpack configuration that leverage the assets-webpack-plugin plugin, allowing the generation of the manifest.json file.
  • The common configuration (/packages/config): This is where the micro-frontend specific configuration lives and can be shared amongst all micro-frontends to avoid copy-pasting it for each micro-frontend.

In conclusion

In conclusion, the Micro-Frontend Architecture we’ve explored stands out for its full utilization of React, which offers a myriad of benefits. By sharing a single instance of the React library, along with other shared libraries, we enable seamless data sharing between the main portal and different micro-frontends, thanks to the React’s Context API . This “single-framework” approach not only streamlines development but also maintains a consistent user experience, even amongst diverse developer teams. Additionally, it results in smaller bundle sizes for the micro-frontends, enhancing performance and load times.

However, it’s important to recognize the challenges inherent in this architecture, particularly in the initial setup and the configuration of micro-frontends bundling. Yet, fear not! The example provided in this article serves as a valuable resource to navigate through this process effectively. We’ve demystified the setup phase, empowering you to overcome any obstacles with confidence.

So, while there may be some initial complexity involved, the advantages of a React-based Micro-Frontend Architecture are undeniable. Armed with the knowledge and tools presented here, you’re well-equipped to embark on your journey towards building scalable, modular, and efficient web applications that prioritize both developer productivity and user experience.