Video Summary and Transcription
Micro frontends are an architectural style where independent deliverable frontend applications compose a greater application. They allow for independent development and deployment, breaking down teams into feature verticals. React Native's architecture enables updating the JavaScript layer without going through the app store. Code Push can be used to deploy separate JavaScript bundles for each micro frontend. However, there are challenges with managing native code and dependencies in a micro frontend ecosystem for mobile apps.
1. Introduction to Micro Frontends with React Native
I'm super excited to be doing this talk on micro frontends for mobile with React Native. A little bit about me. My name is Mo. I am the head of mobile at a company called Theodo based in the UK. We have been doing React Native for a very long time. In the last few months, we were approached by a client to develop a streaming service. With universal apps, the idea is that you write once and you can run anywhere. You try to reuse as much of your core component logic and your business logic across the board. How do we architect a project at this scale? How do we create the right work stream so that our teams can simultaneously develop? One of the things that we did was we tried to take the main features of the application and put them inside of packages that teams could develop autonomously.
Hey everyone, nice to be with you all at React Advanced this year. I'm super excited to be doing this talk on micro frontends for mobile with React Native. It's a topic that I've been exploring a little bit for the past few months and I think there's a lot of interesting learnings and I hope that by the end of it I will have piqued your interest to explore a little bit more in an area that I think is a little bit underdeveloped and there's a lot of scope for improvement within our community. So yeah, hopefully some exciting stuff will come out of this.
A little bit about me. My name is Mo. I am the head of mobile at a company called Theodo based in the UK. Theodo is a group of international consultants, digital experts that are located around the world, mainly based in France, the UK, New York and also in Morocco. We have been doing React Native for a very long time. You may know us by another name, BAM, where we've been working on open-source in React Native since the very beginning. We adopted React Native back when it came out a few months after it was released by Meta, and we've released various open-source projects like the React Native Image Resizer Library, and more recently Flashlight, which is a tool to measure performance for mobile apps.
Being in the consultancy space, you get to experience a lot of different projects, and I want to talk to you a little bit about one of them today. Story time. In the last few months, we were approached by a client to develop a streaming service. Now, this is a full-scale media platform. It's not just streaming with some videos and just a very basic site. It was the full-fledged thing, with news, with streaming, reading articles, listening to podcasts, all centralized into this one platform that had quite a lot of different moving features about it. The key points in this project was that, one, there was a large number of features, but they had a bunch of other requirements that made it more complex. One was that they wanted it to have feature parody across web, mobile, and even TV. They wanted to have very short turnaround, which meant that we needed to have several teams of developers working on this project simultaneously.
So, being a bit familiar with the React Native space, one of the things that we went for when we heard about parody across the board was this idea of universal apps. This is a space that is developing and I think coming to fruition in the past few years. With universal apps, the idea is that you write once and you can run anywhere. You can use React Native really to create a web application, a mobile application, a desktop application, and even maybe a TV application. You try to reuse as much of your core component logic and your business logic across the board and super powerful in the sense that you can have many, many gains in terms of speed and delivery and rate of iteration and innovation. So it's a very exciting space to be in and we knew that this was going to be a good fit because our project was going to be mobile first but they also needed access to web and TV, so it was kind of a no brainer for us. But it also got us thinking about something a little bit more subtle, which was how do we architect a project at this scale? How do we create the right work stream so that our teams can simultaneously develop? We've got tens of different developers working on this project at the same time. How do you organize it in a way where people aren't stepping on each others' toes? People aren't having too many different sort of merge conflicts or too many different blockers along the way of their development. So one of the things that we looked at very heavily was how do we structure this project? Now this is a simplified folder structure, but hopefully it gets the point across. One of the things that we did was we tried to take the main features of the application and put them inside of packages that teams could develop autonomously.
2. Introduction to Micro Frontends
Some of the main features were isolated into separate packages that could be used inside the application. This modular feature-driven design works well for universal and React Native applications. The next natural step is to explore microfrontends for mobile. Microfrontends are not suitable for every project, but they can be beneficial for large-scale projects with autonomous teams. The story of micro frontends begins with the transition from monoliths to microservices in the backend. As applications grow, maintaining a monolithic frontend becomes challenging, slowing down development speed.
So some of the main features were things like watching live streams or reading news articles or maybe listening to a podcast. And so we isolated these features into separate packages that could then be used inside of the application. And these were eventually building blocks that would come together and build the full fledged platform.
And one of the nice things about packaging like this was that we could effectively take any of these modules, isolate them, test them individually, they could be developed in isolation without needing to deal with all of the other stuff that the teams were working with, which meant that the developers wouldn't really get blocked at any point. And this sort of modular feature driven design really works quite well for universal applications and React Native applications.
Because when we started to break down our teams, we saw that we had created these nice feature verticals where a single team was focusing on business logic on the front end, they were creating common React Native components. But they were also coding in Native for iOS and Android and web and really understanding the core of the feature that they were building and becoming specialists in that. We really like that, but it wasn't a new concept. The next natural step that you could take from this was to go down the microfrontend's route.
So it kind of piqued this question in my mind around whether or not microfrontend for mobile is something that is feasible. And so that's what we're gonna explore together today. This is very much an exploratory talk. We're not looking to... I'm not here to advocate going full fledged with microfrontends and adopting them for every single project that you use because that is nonsense. I think there's a lot that we can learn from this approach. It's applicable to a very specific type of project. It can help a lot of projects that are at scale and they're very, very large and with a large number of teams that can be autonomous, but it's not for every single project. So I want to put that grain of salt there just so that everyone is aware this isn't advocating that you should use this on every single project that you go on from now on.
So let's go through a little bit of a history lesson. From monoliths to microservices. So ironically, the story of front ends, the story of micro front ends, starts from the backend where applications started to go from monoliths to microservices. So let's say you've got a basic backend that handles three main features, authentication, streaming and payments. So they're stored under one umbrella application. So all of them fit into one app that is a monolith and so that's fine. That's really three features. There isn't much surface area, but naturally over time you start to add more and more features. And so the app grows. And suddenly as this project is growing larger and larger, you're inevitably stuck with sort of a behemoth of an application. And every single new developer that comes on has this cognitive load that is just massive to deal with. And so the speed of the team will naturally start to slow down and down as you start to build more and more into this application.
3. Introduction to Microservices
Teams often fall into the pattern of working on massive monoliths, which can be challenging. In the early 2000s, the concept of microservices emerged as a solution. Microservices involve splitting application features into self-contained services that can communicate with each other through APIs or event buses.
We've all seen it. It's a common pattern that teams fall into. And it kind of leaves you feeling a bit like our friend Harold here, working on these massive monoliths. So, a lot of people grappled with this in the early 2000s. And this concept of microservices started to come up. And the idea with this was, what if each of these features of the application started to, was split out to constitute its own self-contained service? So, each of these services could be isolated into very specific feature divisions. And they could communicate with those services, maybe by APIs or some sort of event bus.
4. Exploring Micro Frontends in Modern Architecture
Micro frontends are an architectural style where independent deliverable frontend applications compose a greater application. It allows different small frontends to be deployed on their own cadence and schedule, coming together to build a whole site. Amazon's website is a classic example of micro frontends, with the header, navigation section, and promos as separate micro frontends. This approach offers benefits such as breaking down teams into feature verticals, enabling tech agnosticism, and allowing for independent release processes.
And if you're looking at the diagram on the right, it looks pretty scary. It is. But it's not for you. It's for those poor platform and DevOps engineers who have to deal with it. So, you're fine. Those platform engineers are going to be feeling like hero now. So, it wasn't the silver bullet that a lot of people went for. But it did solve some problems of scale for a lot of large organizations.
So, then this concept of microservices started to become more and more popular. People were adopting it left, right, and center. And so, later down the this concept was taken and put into the frontend space to create micro frontends. Now, if you go onto the community-led website for micro frontends, the definition that they list there is that it's an architectural style where independent deliverable frontend applications compose a greater application. So, that means that you have different small frontends and each of these are kind of deployed on their own cadence and on their own schedule and all come together and build a whole site together.
And the classic example of this is the Amazon website. So, Amazon is actually a nice place to see where you could break micro frontends into. So, if you look at the main home screen, at the very top you've got the header. That could be a micro frontend in itself. You've got the navigation section. That could also be a micro frontend. But then you might also have these sort of promos that they've got in boxes within the main part of the page and that could also be a micro frontend. And So, each of these micro frontends comprise and build the larger website.
So, there's quite a few benefits here. You break down your teams into feature verticals so there's less context for each team. And they can really deal with the core of the features that they're building out. That's great. Teams can also be tech agnostic. So, you can kind of mix and match different stacks together. And that means that you don't have to really carry the baggage of tech debt if there's choices that you necessarily don't agree with but other teams might have made in the past. We've all been there. And each of the teams have sort of an independent release process.
5. Micro Frontends and Mobile Apps
Micro frontends add complexity but offer benefits such as independent release cycles. However, mobile apps have different distribution processes, requiring submission to app stores. React Native's architecture allows for updating the JavaScript layer without going through the app store.
So, they can release on their own cadence. And those releases will be just sideloaded off to the user when and where those independent release cycles are completed. So, those are the benefits.
Now, it does come with a very major disadvantage. And that's that you're adding a lot of complexity to be able to achieve this. So, whereas with a normal frontend, you've got a single application that's being published. Here you've got suddenly a bunch of different moving parts. You've got multiple with their own tech. You've got a lot more points of failure that you're gonna have to deal with. And on top of that, you're adding a host layer that needs to manage the shell of the frontend effectively. And that in itself is a lot more added complexity.
And so, this added complexity is something that you're gonna need to consider when you're looking at micro frontends. And so, when you take this to the mobile app, well, how do we split this out? Can we find a similar split? I think we can. If you look at the Amazon application, maybe you can have a product description micro frontend that's a screen of the application. And you can also have a shopping cart micro frontend. So, you can start to split and modularize an app into micro frontends as well. But ultimately, micro mobile apps are quite different to web apps. The key component here is the distribution side. Apps are bundled and released via an app store. You go through a build process, you submit them to the app store. And so, it raises a question around this concept of independent release cycles.
Because even if you take the different screens that we just talked about, put them into modules, so, you have a product details module and a shopping cart module, and then you combine them into a single app, ultimately, you're going to still need to go through that process of submitting to the app store, which is the great, big, scary ghoul that stands at the end of every team's release. And they can either approve or deny your application going through. So, really, the future teams don't have any control over the release processes. And that really ages any developer beyond measure. It's a depressing sight to see. But that is where React Native really comes into play. And this is one of the, I think, the beauties of React Native is this architecture of having a JavaScript layer and also having a native layer. And one of the things that you can do with that is that, you know, if you want to change some of the stuff that lives on the JavaScript layer of your application, what you can basically do is write some JavaScript, bundle that, send that somewhere to the cloud, and the shell of the React Native app can query and basically update the JavaScript layer whenever you want to push out updates to a team. Now, this is incredibly powerful because at any point you can just go in and update JavaScript and not need to go through the app store.
6. Micro Frontends with Code Push
Faster iterations, quicker bug fixes, delivering value to users sooner. Code Push supports a single JavaScript bundle, requiring bundling everything together. But what if we could use Code Push in multiple parts of an application and bundle things separately for each micro frontend? Different instances of JavaScript bundles inside a single native app shell, independently deployed by Code Push.
Faster iterations, quicker bug fixes, ultimately delivering value to your users sooner, everyone's going to be happier, right? I know there's a lot of different implementations for this which for achieving these over the air updates. But one is Code Push that we're going to be looking at. And Code Push is great. But it only supports a single JavaScript bundle, which means you still need to take everything and put them all together. Which was a depressing thing to come to terms with for me. But it still got me thinking, it would be very cool if we could use Code Push in multiple parts of an application and bundle things separately for each of the different micro front ends that you may have and have different instances of JavaScript bundles inside of a single native app shell that could be independently deployed by Code Push.
7. Demo of MyCars Application
I spent a fair bit of time, but we ultimately came up with a demo to show this. I've created a very basic application called MyCars with two tabs, Home and Remote. These are two different JavaScript bundles, two different React Native apps deployed independently. We're going to make some changes to improve the app, starting with the dashboard screen.
I spent a fair bit of time, but we ultimately came up with a demo to show this. And this is very exciting for me, so hopefully it doesn't fail. Let's take a look at the demo.
I've created a very basic application here called MyCars. I don't own any of these cars that I'm about to show you. If we jump into it, it's a very basic app with two tabs. Now, the shell of the app is a Swift app, but the screens inside are going to be built with React Native. This first screen is the Home screen, and that is a single bundle. And then we've also got a Remote screen, which is another bundle. These are two different JavaScript bundles. They're two different React Native apps that are being deployed independently from each other.
We're going to go and make some edits to just showcase how this would work. On the Home screen right now, I've got a little carousel which has a bunch of different cars that I wish I had in my garage, but I don't. And Audi A4, a Bentley Continental, and best of all, a 1970 Opel Corsa with 203,000 miles. So we've got some nice-looking cars here, I promise you. We're going to go in and make some changes. Now I've got a little bit of feedback on this, how we can make it a little bit better. So firstly, good morning. It always says good morning. Probably not accurate right now when I'm recording this, when it's in the evening. So we're going to go and change that. And then also on this, it's a little bit confusing on the remote because it says vehicle open, but this is actually just locked and unlocked. So I had a scare at one point thinking that the cars were left with their doors open when it was just unlocked. So let's go and change those two things. So if I open this up here, I've got a repo set up for the dashboard screen, and that's an independent React Native repo. If you literally look here, all that we've got within this repo is it's a bare React Native app that's got a basic index.js with an app being exported, which is just the single screen for the dashboard. And likewise, here, we've got something very similar for the remote screen. So let's jump in here and make some changes. Let's start with our dashboard. So firstly, we wanted to change it from good morning.
8. Updating Text and Deploying Bundles
Let's make some changes to the text on the main screen and the remote screen. We trigger a code push to generate and deploy the bundles. The challenge is that code push doesn't support multiple JS bundles, so we modify its implementation to handle different bundles. By comparing file names, we ensure that the correct bundle is accessed. After a code push, we close the application and upon reopening, the update is triggered, resulting in the updated text and unlocked vehicle on the screen.
Let's just make it, how are you doing today? And we'll just change the text there. And then at the same time on the remote screen, we said we don't actually want it to be locked or open. We actually just want to change this to unlocked. So let's go ahead and change that. And then what we're going to do is we're going to trigger a code push here. So I've got a script here that will run a generation of the bundle. And then afterwards, likewise here, we're going to do a code push here, which will which will generate the bundle, and then it will make a call to App Center to effectively push these bundles to the cloud. So that's doing that right now, it's going to do a release.
And so if we go into the native side of the code, I've just taken some of the code of snippets. This is very POC and very draft, but just to give you an idea, the way that it works is we've got a React Native view controller. And this view controller uses code pushes bundle URL to access a specific resource. And that resource is going to be passed in by the tab views to say, you know, I want to access the dashboard screen or I want to access the remote screen. Now, the challenge here is that code push, like I mentioned, doesn't support multiple JS bundles. So, with a lot of pain, one of the things that we have to do here is actually go in and change how code push looks for bundle, how code push looks for the bundle URL for a specific bundle that you pass in here. So, when we actually call code push.bundle URL and pass in the resource, we need to go in and modify the actual implementation for it to actually check and make sure that it's not quarrying for the same file. So, it always assumes that you have one bundle. And in this process, what we've done is we've gone in and changed it so that it checks for the actual file name and compares those together. This is very rough, very crude. It's just to get it working with the two different bundles. Ultimately, what will need to happen here is that it will need to be able to handle this kind of in a more generic term, but this just gets it kind of working out of the box right now.
So, effectively, what we do here is we check based off of the file that exists in side of the package, but also the file that exists in the actual app binary. And we make sure that they're the same resource name. And if they're not, we assume that it's another bundle that is going to be used. And so now that we've done a code push, we can go back. Now, what we're going to do for this update to trigger is we're going to actually close the application, and then on the next start of the application when we open it up, the first thing you'll see is it's back in where it used to be, but if we wait a second, it'll query. And then once it knows that there's been an update, it actually updates the application. So now it says, how are you doing today, Mo? Okay, great. That's been updated now. And then if we go on this screen, you can see that we've now got vehicle unlocked. So these two modules have been independently deployed.
9. Microfrontend Ecosystem and React Native Bundling
They live in separate repos and could be developed by different teams. Webpack is the de facto bundler for microfrontends, but Metro is the bundler of choice for React Native. There's ongoing work to make Metro more compatible and suitable for a wide range of uses. The communities around Vite and Rollup have implemented their own versions of module federation, and it's only a matter of time before it comes to Metro. React Native's unique architecture with the JavaScript layer and the Native layer provides massive potential for architectural advances.
They live in separate repos. This is within one repo called dashboard screen, and this one is in another repo called remote screen. And they are being developed. In theory, they could be developed by different teams, and they could be independently published. Awesome.
So we've taken a look at how to use CodePush and React Native to create a very bare bones, basic, microfrontend driven application. Now, let's take a step back and just take an overview of where the whole microfrontend ecosystem and where the whole React Native bundling ecosystem stands right now.
Webpack is the de facto bundler to use for microfrontends, and that's because Module Federation is a key part of the Webpack ecosystem. And Module Federation really comes with all of the right tools as a plugin for you to be able to build really effective microfrontends on the web. There's a lot of great resources on this. I'd highly recommend watching some of the talks by Luca Mesoleri, who works at AWS, about using Module Federation and microfrontends in general. I think there's a cool stuff to learn there. And it's really where the maturity lies, especially on the website.
Now, naturally, a lot of people have been attracted to this for mobile as well. Recently, there's been a new Webpack-based toolkit that allows you to use Webpack instead of Metro as your bundler in a React Native application. And one of the primary reasons for that is to be able to use Module Federation and to be able to build microfrontends within mobile applications. The challenge with this is that Webpack is not a first class citizen in the React Native ecosystem. In the current state, a lot of different parts of the community are moving towards Metro. Back in the day, if you had a React Native for a web application, it would be that you would use Webpack for the website and you would use Metro for the mobile side. Nowadays, if you build a universal app within the Expo ecosystem, it is recommended that you use Metro for web as well. Metro is really the bundler of choice for the React Native community, and most people are heavily investing in Metro. There's a lot of good work that's being done to make Metro more and more compatible and more and more suitable for a wide range of uses. Ultimately, I am very excited for a future in which Metro can maybe support some form of module federation.
Now, this isn't really too far off. The communities around Vite and Rollup have implemented their own versions of module federation. There's a very thriving open source project dedicated to implementing module federation within Vite that's also compatible with Rollup, actually. So there's a lot of good work that can be done and has already been done by other communities around different bundlers, and I think it's only a matter of time before a mechanism like module federation comes to Metro, and I think that's where React Native will end up really shining because of the unique architecture it has with the JavaScript layer and the Native layer. There's massive amounts of power to take some of the architectural advances that have existed on the website and bring it over to mobile. So I'm very excited for that. But there are still some challenges.
10. Challenges with Micro Frontends and Mobile
The theoretical concept of micro frontends doesn't work well with mobile due to several blockers. Native code cannot be code pushed, requiring a well thought out system and build pipeline to manage different teams introducing new native code or dependencies. Updates must still be rolled out through the app store for features that are not JavaScript based.
And so we're going to talk about why this sort of theoretical concept of micro front test doesn't really work with mobile. There's still quite a few blockers. Firstly is Native code. You can code push anything that's in JavaScript but you cannot code push any new native code. And so, as you split up your application into different micro front ends, you need to think of a well thought out system and a nice build and deployment pipeline that will effectively allow for you to manage these different teams as they start to introduce new native code or maybe change their native dependencies and introduce new native dependencies to make sure that you are still rolling out updates through the app store with new app binaries and ship those out to your users whenever you do need to introduce features that are not just JavaScript based.
Comments