Ever more companies are choosing Micro-Frontends. However, they are anything but easy to implement. Fortunately, Module Federation introduced with webpack 5 has initiated a crucial change of direction.
In this interactive workshop, you will learn from Manfred Steyer -- Angular GDE and Trusted Collaborator in the Angular team -- how to plan and implement Micro-Frontend architectures with Angular and the brand new webpack Module Federation. We talk about sharing libraries and advanced concepts like dealing with version mismatches, dynamic Module Federation, and integration into monorepos.
After the individual exercises, you will have a case study you can use as a template for your projects. This workshop helps you evaluate the individual options for your projects.
Microfrontends with module federation allow teams to develop and deploy separate parts of a system, simplifying integration into a common shell. Webpack 5 Module Federation solves the issue of loading separately compiled source code for microfrontends. Version mismatches in module federation can be handled using strategies and semantic versioning. Angular can be combined with module federation using a custom builder. Microfrontends can share data and libraries, and web components can be used to wrap and render components from different versions or frameworks. Module federation allows for version negotiation and runtime loading of microfrontends. React.js can be integrated with module federation, and web components can be used to share libraries across different applications. The bootstrap method and web components wrapper simplify the process of bootstrapping Angular applications and loading web components on demand.
1. Introduction to Micro Frontends
Short description:
Today we will discuss micro frontends with module federation. It works with Angular, Vue, React, and even Web Components. The concept of microfrontends is not new, but now we have the right material to implement it with module federation.
So first of all, it's really a pleasure for me to be here with you and to work with you today on one of my favorite topics, namely on micro frontends with module federation. The examples will use Angular because I'm specialized in Angular, but nevertheless, everything we see today works also with other frameworks like Vue or React, because at the end of the day, it's Webpack, isn't it? And perhaps in some advanced scenarios, Web Components.
So first of all, let me get started with a tiny picture. Perhaps you know this picture here. This is the helicopter that has been designed by Leonardo da Vinci. In 1400 something, Leonardo da Vinci designed this helicopter. In 1400 something. That's quite a thing, isn't it? Because back then not a lot of people thought about flying devices, but Leonardo did. The thing is he only designed it because he didn't have the material for building it. And funnily, nowadays we have the material and scientists tried it out. Scientists tried to build this very helicopter and they figured it would really fly. How cool is that? And somehow this whole story reminds me on the current situation we have with microfrontends. Because the idea is everything but new. The idea has been around for, let's say, several years. I have customers that work with this idea for 10 years. Back then, we didn't even have that term microfrontend. The idea is quite old, but so far, we didn't have the right material. But this is changing now with module federation, which is in the core of these two days workshop. Module federation gives us a straightforward way of implementing microfrontends.
2. Introduction to Micro Frontends
Short description:
Microfrontends are tiny individual parts of a huge system that can be developed by teams. Each team has its own fraction of the overall system and can make local decisions, providing business value on a regular basis. The main motivation is to scale teams so that tiny teams can work on fractions of the system. Module federation is the topic of this workshop, which simplifies the integration of micro frontends into a common shell. Building a shell was difficult in the past, but with module federation, it has become straightforward. The first part of the workshop will cover theory and practical examples of module federation, including dealing with version mismatches and using it with Angular. The second part will involve implementing a micro front-end architecture based on a lab description.
Well, when I'm talking about microfrontends, of course, the first big question is, what do I refer to when saying microfrontends? Well, I'm referring to a huge system that is split into tiny parts, into tiny individual parts that can be developed by teams. Each and every team has its own tiny part, each and every team has its fraction of the overall system and they can do local decisions. They can deploy when they are done, and that means they can provide business value on a regular basis. They don't need to coordinate with other teams that much. They can just do the decisions, and this can even lead to own technology decisions. And the best of this is this brings back the agility of a small team to a huge software product that is built by tens or hundreds of people. So this is the main motivation. Scale your teams so that tiny teams can work on fractions of your overall system. If you just have one team, then perhaps, i think you will see it and feel it during the examples. This here is a total overkill. So as mentioned, this all is about scaling teams and as a good friend of mine told me, teams is pro that means we have to have more than once, otherwise, this will get an overkill.
So the thing is, if we have a lot of tiny micro front ends, somehow we need to integrate them into a bigger common thing. And this is what I'm calling the shell, here we have a very simple shell on the left, and this shell is capable of loading this and that micro front end on demand. And so the user has the impression that this is just one single page application, one integrated application. But from our perspective, it's a bunch of applications that have been developed in an Artakic way that have been compiled in an isolated way and published separately. This is what all of this is about. However, building a shell was a nightmare in the past. We had to deal with a lot of tricks and workarounds. So it was everything but fun. But nowadays, and I've already mentioned it, thanks to module federation, which shipped with Webpack 5, this is really straightforward. And this is the very topic of this workshop. We will look into module federation. We will look into a lot of possibilities, even into some advanced scenarios like dealing with version mismatches to find out how this works, to find out how this can help to build big applications. Regarding the contents, in the first part of this workshop, I will present some theory. This theory is about module federation in general. This theory is about version mismatches or dealing with version mismatches, as soon as you start sharing dependencies. So federated Angular is about how to use this Aldo glider with Angular. For Angular, we need some tricks we don't need for React and Vue. This is because of Angular shielding a lot of details from us with React or Vue, you can directly go with your Webpack configuration. With Angular, you have your CLI and somehow you need to tell the CLI to use Webpack module federation. We will even look into dynamic federation and as a bonus chapter, I have something for you that's perhaps quite interesting, it's about mixing and matching module federation with Web Components to even mix and match different versions of your framework or to mix and match, let's say different frameworks. Of course, we don't do this just for fun, we don't mix React with Angular for fun, we need a good purpose for this, like a migration strategy but like integrating something another team did, perhaps we had a merger in this case, it can be that we have different parts based upon different frameworks. This is something I will show you in the first part of this workshop. And I will not only talk about it, I will also show some life code. In this first part, you can land back and listen my words, of course, we can also discuss, I'm always happy if we have some questions.
And then in the second part, it's mainly your turn. For the second part, I have prepared a lab description, and you can go through this lab description and implement your very own micro front-end architecture. And of course I am here for you to help you if there are any questions. Okay, cool. So before we get started, let me also introduce myself. I am Manfred. I'm a trainer and consultant for Angular. I'm doing a lot of workshops for Angular. In times like this, most of them are done remotely. They are either consulting or trainings workshop. And my focus is Angular for the enterprise environment. That means I help my customers with building huge enterprise scale Angular applications. And besides this, I'm quite connected to the Angularcommunity. I live in Austria, I do a lot of stuff in Germany, and I'm always happy if I can work together with people around the world nowadays remotely, which makes it a bit easier like today. Okay, cool.
3. Webpack 5 Module Federation
Short description:
Webpack 5 Module Federation solves the issue of loading separately compiled source code for micro frontends. Current bundlers assume that everything is known at compile time, which doesn't work for micro frontends developed and deployed separately. Webpack 5 introduces Module Federation, defining two roles: the host (MicroFrontend shell) and the remote (MicroFrontend). With dynamic imports and map names, Webpack allows loading exposed files from the separately compiled MicroFrontend. This architecture is transparent to frameworks like Angular, enabling the use of Angular as intended without the need for additional frameworks.
Let's get started with the first chapter, which is about Webpack 5 module federation in general. Well, the main question module federation is answering is this question here. How to load separately compiled source code? And perhaps you are saying now, hey, Manfred, come on, that cannot be that difficult because we have dynamic imports and we could use a dynamic import to point to a micro front end that has been separately compiled and deployed. The thing is, in theory, this works perfectly, in theory.
In practice, this does not work at all because of all the current bundlers work. All the current bundler is like that back itself or the AngularCLI using that. All those bundlers try to squeeze out the last bit of your bundles. And for this, they assume that everything is known at compile time. Everything, even the lazy parts, need to be known at compile time because everything is compiled together, everything is optimized together, think on tree shaking, and then, and then, everything is cut into chunks, for instance, lazy loading. But for our purpose, this is too late because if we talk about micro frontends, we talk about frontends that are developed by different themes, that are compiled separately, that are deployed separately. We don't want to coordinate that much with other teams, we just want to provide business value on a regular basis as we were a little tiny HRD.
And so, this is too late. We don't want to know the other parts upfront. Yeah, and this very issue is solved by Webpack by Webpack 5 Module Federation. Webpack 5 is there since last October, and with Webpack 5, they also shipped Module Federation. And you know, Webpack is really heavily used out there. And that means on the spot we have a big distribution of Module Federation too as it ships alongside Webpack 5. So, I'm sure you're wondering what is Webpack 5 Module Federation doing. Well, it defines two roles. Basically, it just defines two roles. The first role is the host. In our case, it's the MicroFrontend shell. The second role is the remote. In our case, it's the MicroFrontend. And now we can configure both sides. We can say, hey shell, I want to map a URL, the URL mfe1 in shell point over there to something that's called mfe1 over there as separately compiled and deployed MicroFrontend. This here could be an alias. In this case, it's rather and non-alias because in my situation, it has the same name on both sides. Within the remote, I can expose files. I can say, well, this file with this component, this file with this module, or just this file with this function is exposed for the shell. And when doing so, I'm assigning a simple name and now something beautiful happens. I guarantee you, you will love it. Now you can use a dynamic import. You can use it together with the map names, and that means you can grab over to the separately compiled MicroFrontend. Mapback will do the trick to load the exposed file from there. The best about this is that your framework, for instance, Angular, does not even recognize that we are using MicroFrontend. For Angular, this is just like lazy loading. We go with a dynamic import, that's everything. That means Angular does not even know that we have this architecture in place. And so, you can use Angular as always. You can use Angular as is, as it has been intended to be used. You don't need any tricks. You don't need any meter frameworks. Meter frameworks are rather complicated frameworks you use to orchestrate different MicroFrontend in your browser. No, you don't need it. And this really lowers a big, big bane when it comes to this architectural stuff. Underneath the covers, Webpack is doing the heavy lifting for you. Of course, we need some meter data of our MicroFrontend, and this meter data is exposed by Webpack when building the MicroFrontend, and normally it's called a remote entry or a remote entry point. In production mode, this file has about 2K, and those two K's, perhaps three K's, need to be loaded into the shell. You can do it upfront in a rather static way, like here.
4. Dynamic Loading and Library Sharing
Short description:
You can dynamically load microfrontends using a script load. Module Federation allows sharing libraries across microfrontends, reducing the need to load them multiple times. Module Federation provides strategies to handle version mismatches.
You can even do it in a dynamic way. You can use a dynamic script load to load it on demand. Those two or three K's tell the shell everything it needs to know to interact with this microfrontend, to load it, to share dependencies with it, to call methods.
Talking about sharing libraries, this is perhaps one of the coolest features of Module Federation. You can share libraries. For instance, you could say, you could say, well, I'm using Angular, you are using Angular, so why not just share it? Because it does not make sense to load Angular 10 times because we have 10 microfrontends leveraging Angular. No, in a perfect world, we would just load Angular once and share it across all the microfrontends and of course, the share. And this is as easy as opting in into sharing for this or that library. Just mention your library, like here in your webpack configuration. Of course, this might lead to version mismatches, but we will come to this. You don't need to worry. We will come to this and the good message is Module Federation got you covered when it comes to version mismatches. There are several strategies that help you to deal with such a situation.
5. Version Mismatches in Module Federation
Short description:
Today we will discuss version mismatches in Module Federation. Webpack implemented Module Federation twice, starting with the alpha version and then rewriting it during the beta version to include strategies for dealing with version mismatches.
Yeah, and this exactly brings me to the second chapter I have prepared for you today, dealing with version mismatches. The thing is, and I think that's really a nice story, I know the people behind the Webpack product a bit, and that's why I know they implemented Module Federation twice. First, they implemented the alpha version, it grew into a beta version, and then during the beta version, when they discussed with companies, they figured that they need a beta story for exactly this topic here, for dealing with version mismatches. And yeah, so they just rewrote it. They completely rewrote it, they implemented it one more time to bake in several strategies for this.
6. Version Compatibility and Semantic Versioning
Short description:
The default behavior of selecting the highest compatible version of each shared library simplifies the negotiation process during the shell startup. Semantic versioning ensures that a higher minor or patch version is always backwards compatible.
And even though you can configure several strategies, the good message is, already, their default behavior is a quite smart one. The default behavior is selecting the highest compatible version of each and every shared library. The highest compatible version. Sounds a bit complicated? Yes, I feel you. That's why I prepared a tiny thought experiment. Let's think on a situation where we have Angular 10 on the one side and Angular 10.1 on the other side. In this case, we would go with Angular 10.1 because 10.1 is the highest compatible version. That means when your shell starts up, there is a negotiation, the shell looks, what do we have here? What do we have there? And then the shell figures, well, this 10.1 is the highest compatible one, let's go with this version. And this really fits well to semantic versioning where a higher minor version or a higher patch version is always backwards compatible.
7. Version Mismatches and Web Components
Short description:
When it comes to version mismatches in Webpack 5 Module Federation, both versions will be loaded by default. This can work well for stateless libraries but poses challenges for stateful frameworks like Angular. Mixing different versions of Angular can lead to difficulties in component integration. However, if necessary, web components can be used to wrap and render components from different versions or frameworks, although this adds complexity and increases bundle size. In the end, the decision to use multiple versions should be carefully considered.
However, perhaps we have this situation. On one side, we have version 11. On the other side, we have version 10.1. No. According to semantic versioning, a major version can introduce breaking changes. So chances are high that version 11 introduces breaking changes compared to version 10. And that's why just going with the highest version is not possible. And that's why we don't have a highest compatible version.
So what is Webpack doing now by default? Well, by default, it loads both. By default, it says, well, I see it in the metadata. You need version 11. You get it. You need version 10.1. You get it. This is the default behavior. And of course it's not perfect. It is a hit on your bundle size. You need to download more bytes over the wire. But on the other side, if bundle size is not your biggest concern, then this might be a nice solution because it allows to work independently. It allows one theme to work independently from other things. And if we talk here about, let's say, about a stateless library, then this is completely fine if bundle size is not an issue. Because one part of your application is not concerned if another part of your application is using the same, let's say, underscore version or the same version of RxJS. They just don't care.
However, if we are talking about a stateful framework, you are leading framework like Angular, then this here is an issue because Angular knows all the components. But now here we have two versions of Angular side by side, and yeah, there are some pitfalls when doing this. And besides this, if we managed to deal with the pitfalls, we still have two containers. Angular 11 knows those three components. Angular 10 knows these three components, and the components don't know each other because they live in different worlds, in different universes, in different Angular versions. So using them together is really difficult in this case. If you really, really, really need something like this, then I would think twice, if you really, really need it. And if you say, yeah, I'm still really, really needing this, then you can bring web components into the play. In this case, you can wrap your Angular 11 components using web components. You can wrap your Angular 10.1 components using web components. The good thing is a web component is just implementing a browser standard. That means the browser does not care how this or that component was built. The browser can just make it to render on the screen. And yeah, so we can even mix and match different Angular versions or even different framework versions. Of course, everything is getting a bit more complicated. And if you need some additional workarounds, you have an even bigger hit on your bundle sizes because you'll need to download more. But if you really, really need it, I got you covered. I will come to this very special scenario in the end of this workshop.
Okay, so to cut a long story short, if there is not a HIAS-compatible version, both versions will be loaded. This is fine for a stateless library. If it comes to a stateful framework, go with Web Components in addition. Let me show an example for all of this. This example shows how smart module federation is. Let's assume we have the shell that is using version 10 of something. Let's assume we have a library that is using version 10.1 of something. Furthermore, let's assume we have another micro frontend that is using version 9. And the third micro frontend is using version 9.1.
8. Version Negotiation and Compatibility
Short description:
Module federation allows for version negotiation, ensuring the highest compatible versions are used. You can configure applications as Singletons, allowing only one version to be loaded. However, this is not officially supported by semantic versioning and may result in warnings or errors. It's important to have a sound set of integration tests when using microfrontends, as they turn compiled time dependencies into runtime dependencies. Module federation handles version conflicts and can be used with map components to further decouple dependencies.
And now, because of this version negotiation, module federation will decide to give the shell and the micro frontend version 10.1, because here this is the highest compatible version for both of them, this is the highest compatible one. And it will decide to give micro frontend 2 and 3, version 9.1, because 9.1 is the highest compatible version. Yeah, I think this really shows how well this can work and how this is balancing the trade-off between isolated bundles and using different versions of something.
There are even more possibilities. You could configure an application as a Singleton. That means that this very library can only be loaded once. This is like the Highlander principle, you know, the Highlander principle, there can only be one. So let's assume someone is using version 11 of the Singleton, someone is using version 10.1 of the Singleton, in this case only version 11 is loaded. Even though version 11 is not the highest compatible version, well, it's the highest one but it's not a compatible version to 10 but nevertheless it's loaded because we told Module Federation to go with this Singleton behavior for this very library. And this might be okay or not. It really belongs on your current situation and at the end of the day, you are responsible. You are responsible. Officially this is not working because we have a different major version but perhaps nevertheless it works. If you think on Angular in the last versions of Angular not much changed in the core of Angular. So chances are high that a new major version does not introduce that much breaking. However, because this is not officially supported by semantic versioning, you will get a warning on your JavaScript console when doing this. And if you say well, a warning is not enough because this might be a severe issue, then set strict version to true. In this case, you don't get a warning, but an error message. Fail fast is the theme here, fail fast. You start your application and immediately the shell will throw an error. And this might be a good idea because you don't want your users to discover such a error on runtime. You're bound to discover this error very early, perhaps within your first end to end test, within your first integration test. Fail fast. Don't make the user use it because it's not a nice UX if they fill out hundreds of fields just to get an ERROR because of versions. However, you can also say, well, trust me, I'm an expert. I know this application was compiled against version 10, but I know nothing much did change and I not using that much feature. So it works with everything in this very version range, with everything between version one and 10. It's also possible. But one more time here, you are responsible. The risk is on you. And that also means you need to have a sound set of integration tests. On the other side, you always need a sound set of integration tests if you go with microfrontends. Because what does microfrontends mean? Microfrontends mean that you are turning a compiled time dependency into runtime dependencies. And you never know what happens at runtime. So better have a sound set of integration tests. Cool. So you've seen module federation gets you covered. When it comes to version conflicts. And you can even use map components to decouple everything a bit more.
There is one good question from Alexander. He is asking, does direct version option also fails when requires 10.1, but 10.2 is present? No, this is completely fine. So if there is a highest compatible version, then this is completely fine. And it will just go with the highest compatible version. By the way, and I think you know this from npm in general. You decide what's the highest compatible version by placing the right version numbers in your package.json within dependencies or peer dependencies. Because if you say you need Angular Core in version 10 and if you use this, we call it rooftop, then you clearly say, well, a newer minor version or a newer batch version would be totally fine. If you just use the dildo, then just a newer batch version is fine. So at the end of the day, it's not semantic versioning but you define with your versions in your package.json what's a compatible version. Normally, we go with the rooftop and so the rules are as shown in my little thought experience. Okay.
9. Combining Angular with Module Federation
Short description:
To combine Angular with module federation, we can use a custom builder that delegates the module federation config to webpack. The custom builder then delegates to the default builder to build the application with module federation. If you don't use Angular, you can go with your extended webpack config. I have created a package called angular-architects-module-federation that generates the module-federation config skeleton, installs the custom builder, and assigns a new port for ng serve. Just ng add it, adjust the webpack config, and ng serve your application.
So let's come to the third point I have prepared for you. This is about how to combine this goodness we have seen so far with Angular and especially with the AngularCLI. And here, I have a good message for you, namely the AngularCLI is already using backpack underneath the covers. And since version 12, which arrived about a month ago, we are even using backpack5. So we have everything in place here. However, the CLI is shielding backpack from us. And this is now an issue. Normally this is perfect. Because honestly, we don't want to get in touch directly with backpack. It's quite complicated, especially if you look at the backpack configuration the CLI generates to squeeze the last bit out of your bundles. So normally it's fine that we don't even see it, but now it's not fine because now we need to squeeze in our module federation. And so the big question is, how can we do this? And the answer is we can go with a so-called custom builder. Perhaps you know it. The CLI is really flexible. The CLI has, I always call it a driver concept. You can exchange most of the logic of the CLI and the exchangeable logic for building applications and libraries is part of the so-called builder. By the way, builder is a bit misleading name because builders are also used for executing tests and for executing the Linda. So perhaps executor would be a better name for this. But at the end of the day, it's an exchangeable strategy for some of the commands the CLI provides. And what we could do now is we could now write a custom builder for N sheet build that is delegating our module federation config to webpack to webpack underneath the covers. And then the custom builder can delegate to the default builder. Let's put it here, DB, default builder. And the default builder is doing what it always does. It delegates to webpack to build this very application. But now it's built with our module federation. This is the tiny trick we need here. If you don't use angular, if you use React, Vue, Svelte or something else, the db is now the application. If you use React or something else, then just go with your extended webpack config and you are in business. Of course, we could now write our own custom builder. That would be totally possible. However, you don't need to build it by yourself because I already did it. I created this package called angular-architects-module-federation. I have three things for you. It generates the skeleton for a module-federation config. That means you don't need to learn it by heart. You can just fill in placeholders. That's the first thing. The second thing is it installs a custom builder that enables module-federation. We just discussed this on the last slide. Then, last but not least, it assigns a new port for ng serve so that you can ng serve different microgroup than site-by-site. There are some additional features we will look into a bit later. The usage of it, of course, I'm biased, but if you ask me, it is straightforward. Just ng add it, adjust the generated webpack config, and ng serve your application. And this should be everything to get started if you are a very module-federation-based, micro frontend-based architecture.
10. Micro Frontend Demonstration
Short description:
I have prepared a demonstration to show micro frontends in action. We have a mono repository with a shell and a micro front-end. Sharing libraries is easier with a mono repository. Let's start the demonstration and answer any questions.
Yeah, I know this is all a bit abstract, and that's why I have prepared a demonstration for you, a demonstration that shows everything in action. You can really land back, you can just watch this demonstration and ask questions if there are any, and you will get some time afterwards to work on these topics with the lab descriptions you will get in the second part of the workshops.
So, let's get started with this demonstration here. So in this demonstration, in this demonstration, I need my right folder. Yeah, here it is. We have a so-called mono repository, yes, I trust myself. As feature. I have this so-called mono repository with a shell and a micro front. And no, this is not the prerequisite. You can totally go with different repos. You can have one repo here, one repo there, and integrate everything at runtime. But for the sake of demonstration, it is easier to just use in mono repository. In addition, some people also do this in practice because sharing libraries is a bit easier if everything is here in one repository. There are advantages and disadvantages on this and as I figured, a lot of strong meanings people are fighting over if a mono repo or multiple repos are better. Honestly, I have customers using mono repos. I have customers using multiple repos. Both works fine, but both has different consequences. Here we go with a monorepo. Well, and as you see here, we have a shell and we have a first micro front-end. So let me start it up. For this, I'm going here with my Windows terminal and she served the shell. Let's use a unique port, ends minus O. And do the same here. Let's do the same here, mfe1 or 3000. And we all know Angular. This is now a dining lesson in patience, but together we will make this. Perhaps we can use the time to answer some questions.
11. Module Federation and NX Compatibility
Short description:
When using module federation with NX, there will be no conflict with the NX CLI wrapper around the Angular CLI. You can use the access restrictions of NX to ensure that micro frontends do not directly touch the source code of other micro frontends. Selected libraries can still be shared across them, such as for authentication or passing messages.
Yeah, if I could have a question. Yeah, so we are talking about the monorepos and multiple repositories. The example you showed, I assume this using typical AngularCLI generated project, but often people use NX for handling monorepos and NX is like giving another abstraction layer over the AngularCLI. So what's your approach for module federation also work the same way? Yeah. There will be no conflict with the NX CLI wrapper around the AngularCLI and the done webpack and so on and so on. Yeah, you're right, that really works perfectly. I've tried it out. And it really makes a lot of fun to use this together with NX because in this case, you can use the access restrictions of NX to make sure that one micro front end is not directly touching the source code of another micro front end. But nevertheless, you can define selected libraries you want to share across them. For instance, for authentication or the sake of passing around messages.
12. Loading Micro Frontend into the Shell
Short description:
NX uses the same build as the CLI for applications. Webpack can bind scripts to different remote entry files by defining it in the Webpack configuration. The micro front end needs to be loaded into the shell, even if they are compiled and deployed separately. Module federation is used to load the micro front end into the shell. The Webpack config contains the settings for module federation, while the Angular JSON is extended to register the builder. The same steps are done for the micro-frontend, with a separate step for easier management.
All right, thanks. Yeah, the answer is yes. And the reason is also NX is using the same build as the CLI uses, especially for applications. So, yeah.
I think there was another question. Dennis is asking, how does the script bind to different remote entry files? If you have multiple remote files, how does Webpack know which script points to which remote? Yeah. That's a good question. The short answer is, you can define this in the Webpack configuration. It's both at compile time, but also at runtime. This is the short answer. And the long answer will be shown during this demonstration.
Okay. Cool. So meanwhile, everything started up. Meanwhile, here we have the shell. Here we have the micro front end. And when we click within the shell on flight, we see that nothing works. Because this is now our task, or to be more precise, my task. It's my task to load the micro front end into this very route. Even though we have two different compiled and deployed applications. Here we have low-key host 5,000 and here over there go away, we have low-key host 3000. And no, this is not the prerequisite. You can deploy everything on the same server, but having different boards really proves that we can deploy and compile everything separate. Awesome.
Okay, now let's bring this all to life. Let's use micro front end, let's use module federation to load the micro front end into the shell. And for this as shown on the slides, I'm actually adding the package we've looked into. Yeah, when we see this, then we should append at latest. I'm really curious if you also need to append at latest during your labs. I think I have some issue with my local cache here, I think it's a local issue. Do you want to proceed? Yes, please, I want to proceed. I trust the author of this package. And then, you say, well, I want to activate the shell for module federation. And by the way, the shell shall use port 5000. And now you see a lot of stuff is generated. For instance, a Webpack config with your entries for module federation. You don't need to worry. This is not a full blown Webpack configuration. This is just a partial one. It just contains the tiny settings for module federation. The rest is still generated by the CLR. Thankfully, because Webpack, you know, it can be quite complicated, can't it? So you need to be able to do a lot of things on it. The Angular JSON is extended because the builder is registered, the builder that activates module federation underneath the cards. And some other files are updated. We will look into some of them during the demonstrations.
Okay, so before we proceed with the source code, let's do exactly the same for the micro-frontend. Here I have a separate step for it. It does not need to be, of course, a separate step, but it's a bit easier for my brain to get all this done if I have one step per application. Yeah, I want to enable micro-frontend 1 for this and I want to use the port 3000. By the way, for all of this, they are command line parameters.
13. Exposing Modules and Sharing Libraries
Short description:
If you want to expose a module from a micro frontend to the shell, you can define it in the webpack config. The shell can then load the exposed module. The shared section allows for sharing Angular libraries and handling version conflicts. The shell is a traditional Angular application with the module federation plugin.
So if you don't want to go with an interactive prompt, if you want to scrap this for a huge amount of existing projects, it's possible. Okay, the same happens. Now let's move to the source code. Let's have a look into our micro-frontend 1 and if we would examine this a bit more closely, then we would see it's just a traditional Angular application. Just a traditional Angular application, nothing special in here. Nothing special, but this webpack config, we just generated. This is everything you need to adjust to get that desired behavior.
So it's a partial webpack configuration. You'll see it's not that huge. It's merged with everything the CLI generates. And the most important part here is the CLI, the registration of the module federation plugin. Here, we have two sections. The first section is for remotes or to say the least for micro frontends. The second section is for hosts or to say the least for shells. Here, we are talking about the micro frontend. So let's go with the first section. Let's get rid of the second. Yeah, and now I can expose files. By the way, here we have a unique name for our micro frontend. Here we have the name of the remote entry file. You can call it as you like. If you want to look it cool, you can assign a base 64 encoded string. No, please, don't do it. Normally it's called remote entry or remote entry point. And under exposes, you can define some greedy name. It does not matter, but what matters is you need to point to your file you want to expose. So in this case, I want to expose a flights module. The shell shall be capable of loading this flights module from the remote. And if we look into this, it's really an ordinary Angular module. Nothing special in here. An ordinary module with child rules. How cool is this? Yeah, then here we have the shared section. We already discussed this before. And yeah, of course I want to share Angular stuff. Angular Core, Common, Common HTTP, the router for instance, is what I want to share. And also with this object here, we can define how to behave in the case of a version conflict. What to do if there is more than one version of Angular Core, and if those versions are not compatible with each other. Well, here I'm going, we've discussed this before, with the singleton behavior and the strict version true. Which is most of the times quite a good idea when it comes to Angular, the leading framework. Yeah, that's everything. Besides this, we have a traditional Angular application.
Now let's have a look into the shell. Okay. Here within the shell, one more time we have a traditional Angular application. Everything is as usual, plus we have this webpack.config. And it really looks the same. We have the module federation plugin. We have one section for the remotes. We don't need it because here we are talking about the shell. Here we have the remote.
14. Remote Entry File and TypeScript Compatibility
Short description:
To point to the remote entry file, we can use static federation for local testing and dynamic federation for production. In the shell's routing configuration, we can define a lazy route to load MFE1 using map names. While this is fine for Angular and Webpack, TypeScript will complain about the virtual path. To ease the TypeScript compiler, we can create a DTS file and declare the necessary information there.
And this is one possibility to point to the remote entry file. We can say, well, I want to map a URL mfe1 over there. It's also called mfe1. And this file, port 3000, gives you all the metadata you need to know to load it, to deal with it, et cetera. This is also partially answering the question of Dennis, but this is just one answer. As we will see shortly, there are other possibilities to define this file name for the shell.
Because the thing is if you define this in the Webpack config it's hard-coded. Yeah, it's hard-coded. Even though you define it in the Webpack config because the Webpack config is only read at compile time. It's never read again at run time. And so yeah, that's really hard-coded. This is what I'm calling strict, no, not strict, static federation. And for getting started, for local testing, this is total fine, totally fine. For production, you need a bit more. And this would be dynamic federation. This is what we need for production purposes. We'll be looking into this in some minutes. For the time being, let's get started with static federation.
So the rest is as before. We can share libraries, we can define an object like seen on the slides that tells you how to behave in the case of a version. And what's the question? Now I thought someone started a sentence. And now we just need to load MFE1, we need a lazy route pointing to the URL MFE1. And this can be done in your Shells routing configuration. Here I have my app routes. And here I've already prepared my dynamic route or my lazy route, to say the least. It's as usual, we have a bath, we have low children pointing to a lambda using inboard to load something that we just want to load on demand. The only difference here is we are using the map names. The map names pointing over to the flight module in our remote, in our microphone. This is totally fine for Angular because from Angular's perspective this is just lazy loading. This is totally fine for Webpack because Webpack knows how to resolve this path. We have configured it. However, it is not fine for Typescript. Typescript is complaining. Typescript is saying, I don't know this path here. And yeah, Typescript is right. It does not know this path because this path does not exist. This is just a virtual path. A virtual path resolved by Webpack at runtime. But there is not a file with this name. And now we need to find a way to ease the Typescript compiler. To tell the Typescript compiler, come on Typescript, trust us. We are experts. This will work at runtime. And for this you need a DTS file. The name does not matter as long as you call it VTS, or as long as you assign the ending DTS. And within this file, you can declare your stuff. You can say, well, this works. This is there. And yeah, wow. It's cool, isn't it? Now it's also fine for tab scripts.
15. Starting the Shell and Micro Frontend
Short description:
To start both the shell and micro frontend, you can use the 'run all' script. It's a convenient way to launch all applications in your monorepo. The shell and micro frontend work together smoothly, and you can interact with them successfully.
Yeah, that should be enough. That should be enough. As you have seen, traditional Angular application plus this configuration. So now of course we need to start both our shell and our micro frontend. And if you don't want to work with two windows, you can run run all, which is a script that comes with the back catch we've seen. And yeah, it's just starting all your applications in your monorepo. I wrote it because you can imagine I drove crazy then working with so many different AngularCLI processes. So, yeah, a little concurrency issue because Angular is converting libraries meanwhile on the fly and this is mutual exclusive. So two processes are not allowed to work on the same library, but nevertheless, it looks quite well if you ask me here on Locales 3000 we have the microphone here in the shell. We have flights. Let's reload it. Shall I click on flights? Yeah, let's kick it and yeah, it works. It's always amazing because you know, when doing life coding, then a lot of things happen. The human brain is a wonderful thing until you start programming in front of an audience. Then it's completely stops working, but yeah, in this case, everything is fine.
16. Module Federation and Angular Libraries
Short description:
Module Federation is suitable for loading something not known at compile time, separately compiled and deployed on different servers. If not needed, go with traditional Angular Libraries. Micro front ends are loaded separately, proving Angular reuse. Refreshing the shell is required for new micro front-end versions. Cross-origin resource sharing is not needed for loading source code. Strict versioning leads to runtime errors if versions don't match. State management like Azure X can be shared across micro front-ends, isolating them using interface segregation.
There was a question in the chat. Let me look it up. When should I use Module Federation over Angular Libraries? Well, I would say Module Federation is only the right fit for you and your colleagues if you want to load something that was not known at compile time. If you want to load something that is separately compiled and separately deployed on this or that server. If you don't need this, this plug-in behavior then just go with traditional Angular Libraries. And this here is an Overclicker.
Okay, cool. I always like to look a bit underneath the covers. Let's press F12. Let's have a look into the Network tab when I'm clicking here. And you see it here, only the micro front end is loaded. Only the micro front end with 10K. This really proves that Angular is reused. We are just loading Angular once and then we are sharing it between the shell and the micro front end because otherwise the overall bundle size would be far bigger. And it also shows that from Angular's perspective, this is like lazy loading. From our perspective, it's far more because we talk about something that has been separately compiled and deployed. To prove this, one more time, you can have localhost 3000 and localhost 5000 there, which is not the prerequisite, it's just the proving.
Marek is asking a question, if you will redeploy the micro front-end one, then you need to kick the shell as well. Yeah, yeah, that's true. So the shell is not automatically reloading if you have a new version of micro front-end one, someone needs to press this button in order to get the newest version of micro front-end one or it could work with some notification mechanisms. So I will send events or web sockets to inform the client that it shall be reloaded. But in my opinion, this is not that a huge issue. It's a huge issue on the server side with microservices, but with micro front-ends, I think not much users would assume that their application is automatically refreshed. Refresh is enough, yeah, yeah. No, we just need a refresh. The refresh is enough. Do we need cores? Cross-origin resource sharing? In this scenario, not. If we just want to load source code, we don't need it. And the reason is that VAPAC is creating dynamic scrap decks. And for scrap decks, you don't need cores. You can totally point to another origin with the scrap deck without configuring cores. However, if you want to load some data from an end point over there, yeah, then you need cores or you'll need to tmble it through the Shell's backend. Because here, everything runs in the context of the Shell's origin. Good question. Good question. Another question, when you use strict version, what happens when another team upgrades a remote you use to the next major version and they don't match up at run time. Will your app error out in production? Yeah. So it will get a run-time error immediately. And this is a good thing because hopefully you run a sound set of integration tests before going into production. And because this run time error is thrown immediately, you will very quickly find out that something does not work. What about state management like Azure X? It has fewable store, which could get into a conflict. Yeah, that's true. So, normally you want to share and share X the library, bits and bytes across your micro front-ends because you don't want to load the store 10 times just because of having 10 micro front-ends. However, as the micro front-ends should be isolated from each other, each and every micro front-end should only know its main branch. So, if this is your app root, the app state, the app state, then create a main branch for micro front-end 1. Create a main branch for micro front-end 2. And make sure they don't know each other. You can do this by using interface segregation. That means you create one interface for the app state that is respecting this view and the second interface, how to draw it, is respecting that view and there is not an open app. And so you can more or less guarantee that they don't start interacting without each other.
17. Dynamic Federation and Runtime Loading
Short description:
Micro-frontends are used to decouple domains and tiny parts of the overall system. Sharing a UI library is a common use case for Module Federation, providing a common look and feel. However, the current drawback is that the remote entries in the Webpack config are hard-coded. To address this, dynamic federation is introduced, allowing for runtime loading of micro-frontends based on key data. The routing table can be dynamically set up, and a registry service can be used to inform the shell about available micro-frontends. Restarting the shell is required after changing the Webpack configuration. The micro-frontend and the shell can be loaded on demand, but loading the remote entry at runtime may be too late for version negotiation.
And this is really vital because we always have to think about why do we do micro-front ends? We use this architectural approach to decouple domains, business domains, from each other, to decouple tiny parts of our overall system from each other and so they really should not know much about each other.
Is creating a sharable UI library a common use of Module Federation? Yeah. Yeah, I think so. And this is not an issue because a shareable UI library is not use case specific. Your first and foremost wants to decouple use case specific stuff, but sharing a framework or even a self-made UI library at a science system is totally fine. And I think it's even more or less required in order to provide a common look and feel. Yeah, so the answer is totally yes. Yep.
Yeah, cool. So we have a first running solution and it works kind of nice. Yeah, that's true. However, there is one drawback currently we don't really like, namely if we move to the Webpack config of the shell, currently the remote entries hard-coded. And this is not as flexible as we want it to be. That's why now let's move to what I'm calling dynamic federation. Dynamic federation means we get rid of this setting here. We don't want to configure anything upfront for the shell. Instead, we are moving over to our app routes file. And here we are switching out this import for a helper function that is called load remote module. And load remote module gives you or takes from you three pieces of data, namely the remote entry, which is the file with the meter data, the remote name, which is MFE1 in our case, and the exposed module, which is.slash module in our case. That means we are just providing the key data for loading something from over there at run time. Here, we are really providing strings, and even though those strings are hard-coded here, they can be loaded from some backend. Perhaps we are using I call it a registry service. Perhaps the shell is hitting this registry service on startup to get informed about currently available micro-frontends. And for all of them, we could create a route here dynamically. Perhaps, we don't even know the amount of micro-frontends. In this case, we can completely dynamically set up our routing table. I mean, the routing table at the end of the day is just an array, so setting it up dynamically is not a big deal. Yeah, that should be everything. Of course, I need to restart my shell because I've changed the webpack configuration, so let's do this. This is my in action. I think this looks good. That's fine. I don't know why build.js doesn't support this. Random colors, but I want to have random colors I like, you know? And so I had to invest another two hours. Well, let's have a look at this, the micro front and the shell. And when I'm clicking here, the micro front end is loaded. Let's press F12. Let's reload everything. Let's click on flights. And now you'll see the micro front end is loaded on demand, but also the remote entry chess, the metadata. And here you'll see, boom, here you'll see, boom, it has 28K. I've promised you two or three K's, now we have 28K of metadata. What's going on here? Well, I tell you what's going on here. The back mode it's going on here. If we are in production mode, then it will indeed only has two or three K's. So you don't need to worry about this. However, there is another thing we should vary about. Namely loading the remote entry on demand is most of the times too late. Why is it too late? Well, I've told you before, that module federation is doing version negotiation. It looks at the version we have here, it looks at the version we have there, and then it decides what's the highest compatible version.
18. Version Negotiation and Remote Entry Loading
Short description:
Version negotiation is triggered at application startup. Loading the remote entry point at the beginning is essential for this negotiation. The main TS imports a bootstrap file, allowing module federation to negotiate versions. The dynamic import at the beginning enables module federation to squeeze in and negotiate versions for the imported libraries. The plugin handles the generation of the main TS and bootstrap TS. The metadata file loaded into the shell ensures compatibility and allows running different versions side by side. The metadata is loaded using the 'load remote entry' helper function. After loading the remote entry file, the application is bootstrapped.
This version negotiation, as I call it, is triggered when the application starts. And version negotiation needs this meter data. It contains the versions we use, the versions of all the shared libraries. And that's why it would be smart to load this remote entry point at the beginning when the application is bootstrapped, because we need it for this negotiation.
In this case, we cannot respect everything that's in here. If this year came with a higher compatible version, we could not respect it. It's too late. So in this case, it's a good idea to skip this here and to move this to our main TS. Let's load it before the application bootstraps.
And now you have to be very strong because this is not the main TS you know. Look at this. This is how your main TS looks like. It is just importing a bootstrap file. The bootstrap file and this main TS have been generated by the plugin. When you enter at it, this happens. Perhaps we have fit on the console. No, it's already cleared. It's told you that main TS is changed and that a bootstrap TS is created. So what's bootstrap TS? Well, it's your former main TS. And at first sight, this does not make sense at all. Why to go with a main TS that is just importing a bootstrap TS that in turn is just doing what the main TS did before. What's going on here?
Now, the important piece of this here is that this import is not a static import. This is a dynamic import, a dynamic import that returns the imported file using a promise. You see, in the case of an error, I'm catching the error of this promise. And this dynamic import gives module federation the opportunity to squeeze itself in here. Module federation squeezes itself in here. It looks at the bootstrap file and at everything bootstrap is importing, and so it knows which versions to negotiate, which versions for which libraries to negotiate. Here it knows, we need angular-core. So let's negotiate the version we want to use for angular-core. We use angular-platform and so on and so forth. We even have indirect dependencies like at module is using, I don't know, angular-router. All of this is negotiated here and this is only possible because we have a dynamic import at the beginning, and the good message is the plugin got you covered. It's generated all of this for you.
So there was a version in the chat, if the strategy, Marek is asking, if the strategy for dependencies versions will allow all versions, what will happen if the version of Microsoft Round&One will change during rundown? Well, shell install that dependency or download it from the Microfront and one remote entry. No, the answer is nothing will happen. We only know what we have in our metadata, what we have in this metadata file we are loading into the shell. But normally that's not a big deal because the user can press F5. And even though we have also in newer version, in the meantime, each bundle has a hash value as part of its name. And so there are no conflicts. That means we can run different versions side by side. This shell can run version nine, this shell can run version 10. So there is no magic for this.
Okay, so this is the right place to squeeze in our metadata and to load the metadata, there is another helper function called, load remote entry. We are passing the name of the remote entry file, the URL, and the name of the microfrontend. Of course, this is, this is asynchronous one more time, that means after loading this, we can go on left that guy. Yeah, and that's it. First of all, we are loading the remote entry file, and then we are bootstrapping the application. Of course, this does not need to be hard-coded. You can fetch this data using the fetch method from some registry.
19. Data Fetching and Sharing in Microfrontends
Short description:
You can fetch data using the fetch method from a registry API for micro frontends. However, since Angular cannot be used, you need to use fetch or XHR. Sharing data between microfrontends can be achieved through a shared library that holds the necessary data. In this case, the library is called Outlip, an authentication library that includes a service to hold the current username. Authentication can be simplified when everyone is honest. Let's explore how to share something that is part of our Monorepo by generating a library and testing it out.
You can fetch this data using the fetch method from some registry. It should be as my registry API micro frontends, and perhaps this gives you all this data you need to load. However, you need to use fetch or XHR because you cannot use Angular for this. Here you have an HANAc issue. We did not even bootstrap Angular because we need to decide which version to bootstrap. And so, we cannot use the Angular based API so we cannot use the Angular based HTTP client but fetch got your covered.
Okay, that should be everything. Let's try it out. Everything was reloaded. I'm happy about this. Let's reload this here. Let's click on flights. And yeah, it works. And now only the micro front end is loaded. The meter data was loaded up front. Let's repeat this. Yeah, it should be somewhere remote entry from over there, localhost 3000. Nice. Okay.
I have one more thing for you before we go into the first break. And before we start with the exercise after the break, namely communication between microfrontends. Sometimes you need to pass some data around your microfrontends. Perhaps it's a security token to have a mutual login. Perhaps it's some kind of key data who is the current customer. What is the current time frame we are talking about? If you think about an accounting solution, then perhaps you want to share the time frame you are talking about. You don't want to select the same time frame in each and every microfrontend time and again. You don't want to select the same tenant, the same user, the same patient in the hospital time and again in each and every microfrontend. We need to share data. The good message is we already know everything to share data. We just need a shared library, a shared library that holds the shared data. Could just be a variable, could be an object, could also be some message subject, if you think about RxJS so that you can do messaging. Just share a library. Can be your very own library, My Company Data. I do all of my programs here. I know all of my libraries, and I know my members, I know everyone here. I connect all access, and I have my cell phone, and I have my RxJS which can be shared with everyone. The big question is how can we share something that is part of our Monorepo? Well, let's try it out. For this, I am generating a library. I'm calling it Outlip, authentication library. And this authentication library will get an Outlip service. So for me this service is good enough and this service will just hold the current username. I don't have strict mode, hence, assigning now is completely fine. And I have a login method. It takes username and password and it logs in the username. This is what I'm calling authentication for honest people. I found out that authentication is far more easy if everyone is honest. And of course, for our purpose, this is good enough.
User name.....service.ts module, federation plugin example, Visual Studio Code. Oh, what's what happens here? Did you hear this? I think this was the screen reader, yeah, so it started talking with me. So this here is my username for WordPress.
20. Using the Off Lip Service
Short description:
I'm going to use the off lip service in my shell and micro front-end to read the username. In the shell, I'll use the OutlibService in the constructor, while in the micro front-end, I'll fetch the username and bind it to the output.
So I'll enter my username correctly. This here is my off lip service, and hopefully it's exposed by the public API of our library, yeah. We are lucky. So as this is a monorepo, normally we create a bath mapping, a bath mapping pointing to this library, a bath mapping that looks like an ordinary NPM package, but in real world, it is just pointing to this library. For this, let's jump into the DS config. Jason and here we have fit off lip. Normally, when going with the AngularCLI, it points to the distribution folder. When going with an axe, you should really look into it. It points to the source. And this is what I'm preferring because I don't want to recombine everything after it's changed. So let's go to off lip. The projects all flipped, do I have Intellisense for stuff like this here and there should be the public API somewhere. It's given within the source folder, public API there. This is how normally a mono-repo works. We are defining names that look like the names of npm packages and they point to this or that file. We could even use some prefix, something like this here. Would be totally fine. Okay. Now let's restart the TypeScript language service, because Studio Code is only reading this file once, namely when we start Studio Code or if we open a folder. That's why we need to restart the TypeScript language service so that this new setting is read. And now we can use it. And now we can use it. So I just use it as in each and every Monorepo. I'm going to my shell. My shell has somewhere a app component. I'm using it in the constructor. How was it called? OutlibService. OutlibService. I love IntelliSense. I even got the right map name, which is beautiful. And here I'm saying, Hey people, I am Manfred. Buzzwords. I don't know. It does not matter. Yeah. And over there in my micro front-end, I want to do the same, but I want to read this username. Let's go over to the micro front-end. Flight search is beautiful. Here, ignore everything that's in here. Private this and that. I love it because very often IntelliSense has an issue. But today it really works. What a beautiful day. And. You, excuse me, this is not a reactive approach. It would be even more beautiful if it was reactive, if a behavior subject, but for the time being, let's go with this non-reactive approach. Let's fetch the username into something I'm calling username. And then let's bind the username to our output. Current user. Yes.
21. Configuring Module Federation for Sharing
Short description:
In order to share the authentication library and hold the username at runtime, we need to configure Module Federation to share everything. By registering the name and map name in an array, the tooling and plugin will handle the heavy lifting. This needs to be done on both the micro frontend and shell sides, just like with other shared libraries.
And that's. So in this case, this works, but nothing will be shared. Perhaps we can look at this at run time. We are here. We are there. Did we have an error? Nothing is loaded anymore. We are here. We are there. As you see, the username is not shared. And the reason for this is that both the microfrontend and the shell is separately compiled, and we did not tell Module Federation to share this authentication library, holding the username at run time. It means we need to configure Module Federation to share everything at run time. And as mentioned before, normally you would place here your npm package. However, our out library is not npm package. It just has a name that looks like the name of an npm package. Well, I discussed this with the Webpack team. The founder of Webpack is from Germany, so it's quite easy for me to discuss with him and he told me there is a way to do this. You can tweak module federation to assume that a library is just in a folder somewhere here or there. And the tooling here is just doing the heavy lifting for you. Everything you need to do to get started with this is register the name, the map name here in this array. And the rest is done by the tooling, by this plugin, in a way the founder of Webpack told me it should work. Yeah, that's everything. The magic is done underneath the covers. And of course we need to do this twice. Each and every micro frontend and shell needs to opt in sharing. That means I have to mention it on both sides, but that's quite the same situation as with the other shared libraries. Both sides or all sides need to opt in.
22. Sharing Data and Lab Introduction
Short description:
You can share data using local storage, index DB, or session storage. Micro-frontends have access to the shell's storage. The webpack config is still needed when using load remote entry and load remote module. Many companies are already using Webpack 5 Module Federation in production. It is beneficial for scaling teams. Now it's time for you to try everything out in the lab.
Okay, that's it. Let's cross fingers. Let's npm run all this again. Okay. Yeah, you know, this log from the CLI. Okay, everything should be fine. Does not know a thing, of course, but the shell is setting the username. I'm switching over here and hey, here it is. That means, we really managed to share data. Saying this, don't share too much data. Normally a handful of properties should be enough because as mentioned before, you don't want to couple everything to each other. This architectural style is for decoupling and if you share a whole store or a lot of properties, you create coupling something you want to do prevent.
Nice, do you have any questions so far? Yeah, sorry. Yeah, you can totally share data using a local storage or an index DB or a session storage that's totally fine. Everything here runs in the origin of the shell that means each and every micro-front-end will have access to the shells, indexed DB, local storage, session storage. That's really totally fine. They even have events that notify you if a key changes and for instance, I really like to do this to share access tokens because normally existing libraries use one of those mechanisms to save an access token and that's why sharing it is quite straightforward.
Dennis is asking, if you use load remote entry and load remote module, do you still need that back config? Yeah, you still need the webpack config because you need to define what to share, you need to define the key data for the remote, for the microfrontend, you need to define the key to do for sharing for the shell. Everything you don't need when going with dynamic federation is this here, defining the pointers, the mappings from the shell to the microfrontends upfront with dynamic federation. This happens at runtime. Are there any other questions? Awesome. So, oh yeah, there's one more or two more questions. Do you know some company that already uses Webpack 5 Module Federation in production? Uh, yeah, I know several companies that are using it. A lot of companies have been looking forward to it because it really lowers a pain of them and I cannot tell your names of course but beyond those companies you find big software vendors, international ones, big banks, big insurance companies, also companies from the industry and telecommunications. So really a lot of companies are looking forward to this and some of my customers are early adopters for this. And it really makes sense if you want to scale your teams. If you only have one or two teams, this really might be an overkill especially because you are exchanging compile-time dependencies for run-time. Are there any further questions before we proceed with a break and with exercises? Now it's your turn, now it's time for you to try everything out I've shown you so far. And for this you will get your lab descriptions, by the way one of the first things you will do in your lab is this here. This here and she adds Angular Architects Module Federation. And for some reason on my machine, I always get an old version and I see this then looking at this line here. When this yellow error message comes or let's call it warning, it's a warning, then you have an old version of this library. In this case, you need to add at latest then everything should be fine. So I would be really curious if you need this at latest. If this comes this yellow warning, then you need it and control C. Cancel it and repeat it with at latest. And perhaps you can tell me via the chat if you need that this at latest or not. Okay. So let's get started with the lab. The lab, by the way, guides you through all the steps. There is a first part, a second part, a third part. And I would say everything after part four, everything after part four is a bonus. That means the goal is that everyone makes part one to three. And if you have some time, part four and five is also fine. But the goal is that everyone makes part one to three. If you have any questions, feel free to reach out to me. I can open a breakout session so that we can do a one on one to solve your very issue, to share your screen, to discuss your current situation. So don't be shy. Reach out to me, and here you have the URL. Here you have the URL.
23. React.js and Mixing Frameworks
Short description:
React.js is not shielding webpack, so you can directly interact with your webpack configuration. You can merge what you learned today with your existing react application. I have an ebook that covers marginal federation and micro-frontends, along with strategic design. I've also published Marginal Federation Tours for mixing and matching different versions and frameworks. Combining web components with module federation allows sharing libraries across different applications. However, this increases complexity and requires workarounds. I've created a library to shield these workarounds and demonstrate its functionality with additional routes.
Enjoy, tell them. Ulfred, I have one question for you, if I may. Yeah, go ahead. I want to go forward to React.js, actually, with that, but I intentionally joined here because I just wanted to see how does it work for Angular. And I know that you wrote this plugin, Angular Architect, right? So do you need a similar thing, or is it already available on React for React.js? Yeah, so the good thing when it comes to React.js is that React.js is not shielding webpack from you. Even if you start with Create React, you can eject from Create React and directly interact with your webpack configuration. And that means you can just take the generated or the hands made webpack configuration and add to it what we added today with the plugin. Something like those settings here. So if you merge what you learned today with what you already have in your react application, your existing webpack config, then everything should be fine. Okay thanks. Very well. Cool presentation, thanks. Thank you. Okay, great. It's 9 p.m. So let's go on with some additional advanced stuff. So first of all, I have a little present for you. I have this ebook. And meanwhile, it has about 100 pages and it's the third edition. And about the half of this book is about what we talked about today. It's about marginal federation and micro-frontends. The other half is about an accent domain driven design or to say the least about strategic design. If you want to read this, then you can find it here. Here you have to hyperlink. Okay. That's the first thing I wanted to tell you. The second thing is so far we've worked with this plugin. Angular architects, marginal federation, which is enabling marginal federation for the AngularCLI. Recently, I've published another package, which is called Marginal Federation Tours. And originally I didn't want to publish it, but I really saw a need for it because some people want to do something like this here. They want to mix and match different versions. They want to mix and match different frameworks. I mean, this here is an extreme example, but I think it shows the point. It shows that it's possible if you combine web components with module federation. Because when doing so, and I think this graphic here shows it, you get the best of both worlds. When doing so, you can share libraries across different applications if they use the same version or a compatible version. Here for instance I'm sharing Angular in the version X between the shell and the microfrontend and I'm using Angular Y for microfrontend to and microfrontend free. Of course, this is a hit on the bundle size but it would be even worse if each and every microfrontend came with its very own Angular version, then possible, we are sharing. And because we have web components, we can also hide the used Angular version or the used framework, the rest of the application does not care. And so we can combine react with Angular with other frameworks. However, doing something like this increases the overall complexity and calls for some workarounds. And that's why I would think twice or even three times before implementing something like this. But if you want to implement it, it's possible. However, when teaching this I really figured it was somehow hard to teach this because I needed to talk about so many workaround to make this work in a more or less seamless way. And to prevent you from using those workarounds I've created this library. This library is shielding those workarounds from you. It is hiding those workarounds behind some helper functions. So before I show you what this library does for you let me show this all in action. Meanwhile, I have updated our project. I had some time during your deep delaps and now I have some additional routes.
24. Micro Front-ends and Angular Versions
Short description:
This part discusses the challenge of different Angular versions in micro front-ends. It explains how bundle sizes are affected and how version negotiation works. The text also provides examples of wrapping Angular, AngularJS, and React components as web components. The process involves using Angular elements and creating custom elements. The same approach can be applied to other frameworks. The text concludes by mentioning the ability to expose the entire bootstrap file of an application as a web component using module federation.
Like this react route, which is loading a micro frontend wrapped in a web component using react. Here I'm using a different Angular version, version 12.3. Here I'm using the same version. The shell is using 12.0.0. Here I'm using 12.0.3. This is also a Web Component which has its own router which brings another challenge because now, somehow we need to tell the shell that the shell is only interested into this part of the route and the inner router is interested into the rest. Yeah and just for the sake of completeness, here I have a few Web Components at AngularJS which shows that all of these can be used for upgrading your applications. Upgrade it little by little, slice by slice, domain by domain, as you want to call it.
Well, there is something that's really interesting here when it comes to this scenario and it's about bundle sizes. So let me have a look at the network tab, let me reload the welcome page and let's load our flights web component. As mentioned before, this web component is really slim, it has about 11K because here, the Angular framework itself, it's shared with the shell, we don't need to load Angular one more time, Angular itself is shared with the shell. If we load React, it's hidden within a web component, then we see, of course we need to load React ones, which has about 40K and then we have some additional case for the application itself. If I am loading another web component using a different Angular version, then here we see the need to load Angular common, Angular core, look at this here, Angular common, Angular core and so on and so forth. And if you look at the numbers here, it's quite huge. We need to load another 100K for this very Angular version because here as mentioned, I'm using 12.03 and the shell is using 12.00. Perhaps you will say now, well, they should be compatible to each other. Yeah, they should be compatible to each other and they are, but just to show this how it behaves if you have different Angular versions, I did remove this rooftop. With this rooftop, everything would be okay. In this case version negotiation would tell the micro front-end shell to just go with the highest compatible one. I've removed this, and so 12.03 is not compatible to 12.00. And that's why it's here loaded one more time. However, if I load the second micro front-end, using 1203, only the source code of the application is loaded because Angular 1203 is already loaded. It came with this Angular one micro front-end here. So we can share it, even though it's additional Angular version we can share it across our micro front-ends and the same happens here with Angular three, only the source code is loaded. The rest was already loaded with the other Angular micro front-ends. And for the sake of completeness, here we have a few, it's quite a tiny framework and Angular chess, which tells us we can use this for migrating everything step by step. So to make this work you need some work arounds as mentioned, those workarounds are hidden by my tools library, you can use it. The first screen here or the first example in the read me shows you how to expose an Angular application as a web component. And this is indeed quite straightforward. You need this package Angular elements, it provides you with a method called create custom element. And in your app module, you can create then this ng do bootstrap method, it's automatically called by Angular, if you don't have any bootstrap components. And look what happens here, I'm calling great custom element, an Angular component goes in a custom element goes out, a custom element or as most people would say, a web component. And then we are registering this custom element with a browser API under this or that name. So this is what it takes to wrap an Angular component as a web component. Perhaps you are wondering how to do something like this with AngularJS or with React, well, you just need to write such a component by hand and then wrap it with a handmade web component. I have even an example for this. For instance, this here is React. I'm not a React expert. So, I'm sure I did something that should not be done. However, this is everything you need to do to wrap a React component inside of a web component. Create a naked web component, which is a class extending HTML element. HTML element has this method here, connected callback. It is called when the web component is added to the dome. And within here you can render your React components into this, which is the web component itself. So, everything you need is this tiny wrapper. And then you need to register it under this or that name and you are in business. And obviously the same works with AngularJS and all the other frameworks. So what we can do now is we can expose the whole bootstrap DS file. The whole file that is bootstrapping our Angular application or our React application or our Vue application under a given name using module federation. Which would be that components here.
25. Bootstrap Method and Web Components Wrapper
Short description:
This library provides a bootstrap method that takes care of the workarounds needed when bootstrapping an Angular application. You can define the key data of your web components, micro front-ends, and module federation remotes using the web components wrapper. The wrapper component will load the web component on demand, and additional helper methods are available to simplify the process. A tutorial is also provided for introducing routes and hyperlinks to web components deployed on the internet.
To deal with all the workarounds we need to do when bootstrapping the application. This library has this bootstrap method. It takes care of all those tiny workarounds that needs to be drawn in consideration. Just call it instead of bootstrapping your Angular application in a traditional way.
And then it's becoming easy. Then you can directly route to your web components. For this you have a web components wrapper. And this allows you to define the key data of your web components, of your micro front-ends, of your module federation remotes using this data object here, which is always part of your route object. This is your configuration. And you see here, we have done this before. We are pointing to the remote entry. We are pointing to the remote name, to the exposed module. And we are also pointing to the name of the exposed web component. And that's it.
Now you can route to the wrapper component and the wrapper component will load this very web component on demand. And if you look through this readme, you will find some additional helper methods, which eases the pain of doing a scenario like this. I even have a tutorial for this. I think we will skip this tutorial for today because it's already quite late and the tutorial is quite easy. It's about introducing several routes pointing to this or that web component deployed to the internet. And then adding some hyperlinks for those routes. But if you want to do this tutorial, feel free to go through it. Of course, I'm giving it to you, please find it now in the chat. Bonus tutorial, bonus tutorial. Feel free to go through it. If you really need a scenario like this. Okay. And that's it. So, thanks for coming. I hope you enjoyed it.
Did you ever work in a monolithic Next.js app? I did and scaling a large React app so that many teams can work simultaneously is not easy. With micro frontends you can break up a frontend monolith into smaller pieces so that each team can build and deploy independently. In this workshop you'll learn how to build large React apps that scale using micro frontends.
Get started with AG Grid Angular Data Grid with a hands-on tutorial from the core team that will take you through the steps of creating your first grid, including how to configure the grid with simple properties and custom components. AG Grid community edition is completely free to use in commercial applications, so you’ll learn a powerful tool that you can immediately add to your projects. You’ll also discover how to load data into the grid and different ways to add custom rendering to the grid. By the end of the workshop, you will have created and customized an AG Grid Angular Data Grid. Contents: - getting started and installing AG Grid - configuring sorting, filtering, pagination - loading data into the grid - the grid API - add your own components to the Grid for rendering and editing - capabilities of the free community edition of AG Grid
Discover Micro Frontends with Module Federation. Learn about the benefits and pitfalls so you can decide whether Micro Frontends are a good fit for your organization.
A workshop for UI and Angular beginners alike. Let's pull down the Tour of Heroes app (written John Papa and found throughout the Angular docs) and give it a UI upgrade! All you will need is a laptop and your favorite data set (mine, of course, will be ponies.)
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
What do you do when you're a framework that's survived and innovated in two JavaScript Framework Waves, and see the new wave cresting in the distance? You innovate. In this talk, we explore the JavaScript Framework landscape, and some of the major competitive features we've seen. We'll explore what Angular is introducing today and where we're headed in the future.
Many companies worldwide are considering adopting Micro-Frontends to improve business agility and scale, however, there are many unknowns when it comes to what the migration path looks like in practice. In this talk, I will discuss the steps required to successfully migrate a monolithic React Application into a more modular decoupled frontend architecture.
In this talk you'll learn all about the renaissance Angular has been going through! First, we'll look into how the framework embraced fine-grained reactivity with signals to boost its runtime performance by orders of magnitude. After that we'll dive into applying a similar fine-grained approach to code loading to make everything load faster. At the end, you'll learn about the tooling you can leverage to land all this in your apps!
The talk will be a story of how Personio went from rendering through a Monolithical PHP architecture, to a microfrontend oriented Next JS app, powered by Module Federation and the NX monorepo toolchain.
Micro frontends architecture is extremely powerful when it comes to splitting large frontend monoliths into smaller, individually deployable blocks, each is owned by an autonomous team and is focused on a business domain. But what about State? We are often told that micro frontends shouldn't share state, as this would make them coupled to each other. However, when it comes to complex UIs, it is not rare to encounter scenarios where state management between micro frontends is necessary. This talk is about finding the sweet spot — In which scenarios it is reasonable for micro frontends to share State? and how should micro frontends share State while remaining decoupled of each other? We discuss & compare different solutions in React.