As you probably noticed, I am a huge fan of React Router 6!
It is Remix for Single Page Applications and gives your apps "super powers" while taking you closer to the platform.
You also know that I love working with large frontend applications, and my passion is frontend architecture at scale, especially Micro-Frontends. So, where is the intersection between these two technologies?
React Router 3
My journey with React Router and Micro-Frontends started at American Express, working as one of the maintainers of One App, a server-side rendered React Micro-Frontend framework (That's a mouthful!)
At the core of this framework was React Router 3. It was so powerful, versatile, and one of the best-designed libraries for React. (At over 1 Billion downloads, the team behind it must have done something right 👏)
React Router 4/5 was released with improved support for hooks. Still, we could not upgrade because of missing features from v3, like the ability to pull the entire route tree programmatically using
childRoutes so we created and maintained a fork of it.
Then React Router 6 came along 🎉, bringing back most of the great concepts from v3 and doubling down on one of its killer features, Nested Routing.
First, what's Nested Routing? An image speaks volumes, so take a look at this:
I haven't found a better explanation than this visual demo from the Remix page, but in Michael Jackson's words:
"It's a way to split a webpage into more granular pieces. Those pieces match a segment of the URL. When you have such granularity, you can perform lots of really interesting optimisations and enable workflows that are difficult when you don't have that concept."
Hold on a second, "Split a webpage into more granular pieces." That's precisely what Micro-Frontends are about!
Combined with techniques like "Runtime Composition", those smaller pieces can be developed, tested and deployed independently by separate teams. React Router nested routing will take you halfway there, helping you split your application in a predictable and performant way.
"For a system to be distributed, it has to be decoupled first."
React Router builds on top of Nested Routing to separate your application's data loading, error handling and rendering.
In a Micro-Frontend architecture, it is essential that your UI is composable, encapsulated and, most importantly, decoupled.
Separating the data loading from the rendering is a fantastic decision for performance (Fetch before you render) and parallel fetching, but this also has a nice side effect on composability and separation of concerns.
One of my "Rules for Micro-Frontends" is that each Micro-Frontends should load its own data. Having every route segment matched to a loader ensures that your data dependencies are explicit and removes indirection.
This makes ownership, refactoring and flexibility features that are baked-in into your architecture.
Another of my recommendations is to avoid sharing state to prevent "accidental coupling". This will keep your application from becoming a "distributed monolith", and you will get most of the benefits of a Micro-Frontend architecture.
React Router 6 loaders and actions remove most of the "global state" needs and greatly simplify React Applications. The URL becomes the "global state" and keeps things decoupled while ensuring all the different parts of your UI are in sync while relying on the web platform.
React Router and Micro-Frontends are great for migrations! (I need to write a separate blog post on this section alone) but in summary, the flexibility and route-matching algorithm of React Router enables you to migrate legacy applications piece by piece and do a "Reverse Strangler Pattern" migration.
What about Remix?
Remix shares most of the best traits of React Router, and I recommend it 100% for new applications. It removes a lot of the pain points that tend to send people down the Micro-Frontends path; however, Micro-Frontends are meant to solve an organisational scaling problem, so at some point, for large organisations it would be great to have independent deployability of segments of a Remix application that are owned by an entire team.
The technical problem is runtime composition. It is possible, it has been done before by Jacob from Remix and my friend Adrien, but for a Framework like Remix, there are loads of nuances that need to be addressed to get the benefits of independent deployability.
TLDR; it is possible, but someone needs to sit down and design a good playbook around it and tweak the tech to support it. (don't look at me!)
React Router is a fantastic tool! Add independent deployments and runtime composition on top of it, and you end up with a robust Micro-Frontend architecture that can help you scale your teams and solve your organisational scaling problems.
Top comments (0)