Is Module Federation Right for You?

Rate this content
Bookmark

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.

191 min
04 Jul, 2022

Comments

Sign in or register to post your comment.

Video Summary and Transcription

This workshop on micro-frontends covers topics like dependencies, communication between federated modules, team organizations, and code sharing. It emphasizes the benefits of module federation and micro-frontends in enabling continuous operation and collaboration. The workshop provides practical examples and discusses the challenges of managing breaking changes and handling conflicts. It also explores the use of React as a view rendering library and the importance of sharing data and controlling communication between feature apps.

1. Introduction to Micro-Frontends

Short description:

Thank you all for joining our workshop. We'll start with a primer on micro-frontends and their benefits. Then we'll work through examples and discuss potential system-level architectures. I've worked with Module Federation and Microfurence extensively, delivering them to numerous countries and millions of users. During this workshop, we'll cover topics like dependencies, communication between federated modules, modulation in hybrid apps, team organizations, and code sharing. We'll also have a Q&A session. My goal is for you to leave this workshop feeling knowledgeable and prepared to implement micro-frontends in your projects.

Thank you all for for joining our workshop today. We have about 2 1⁄2 hours to talk about module federation, but we really cannot talk about module federation without talking about micro-frontends. So we're going to do a little primer on what micro-frontends are and why they're helpful, why we are here. And then we're going to work through examples.

When we are done with the examples, if you're still on board with module federation, I'm going to also show you a few slides on potential architectures, the system-level architectures that you can choose. And I'm also going to show you some slides that I've learned to work well when presenting micro-frontends to bosses, businesses, clients, and so on. Things that they like to hear, because usually they don't speak the language of engineers, and I kind of want to share some of that. So you have it. The slideshow is going to be in in the github repository, and I'm going to share with you in just a minute.

But before we do, again, I'm going to take a second to introduce myself. My name is, well, Gregor is the easy way to pronounce it, the official way would be Gergoor, which I know is terrible, lots of rolling R's. But I've been working with Module Federation and Microfurence for a while, and I'm not the inventor of any of this. So if you know people like Zack Jackson, who I think he's the mastermind behind Microfurence and Toby Carver from Webpack, those guys are incredibly smart. I did spend a lot of time with those two in late 2020 when Madoff Federation was out, because we used that extensively with some, I'm not going to mention names, but some of the big companies out there, big in communications, in auto industry, in pharmaceuticals. You're going to see their logos at the end, but I'm not going to mention them. So I've been working with micro-finance for a long time and delivered them to about 200 countries, and I think lots of millions, users are already, have already accessed some of those stuff, some of those micro-finance that I help architect to create. And today, I only want to share that experience with you. I want to share, you know, we've been through a lot of amazing discoveries and difficult times, difficult problems to have. Because these are highly scalable systems. Scalable in terms of infrastructure, scalable in terms of scalable teams, multinational. So if you work with any of those, you know, this is hopefully going to be of use to you.

So during this workshop, we're going to be talking about, again, what microfrontends are and why your business or your client's business should care. We're going to create a very, very simple Module Federation app cluster. It's going to be super simple because this is an intra-level workshop. And there's going to be plenty of stuff to show, plenty of problems and solutions to show through that very small cluster. We're going to show how to deal with some of the most common issues like working with dependencies, how to deal with problems that you get when you work with dependencies, types of dependencies, and strategies for dealing with different types of dependencies. Then one of the most common questions is how we communicate between federated modules. And I think communication is where you make it or break it. I am going to briefly mention or briefly talk about modulation in hybrid apps. So it doesn't have to be web only. It can be hybrid. It can be completely universal whether it's web, PWA, desktop, or mobile. There are some very interesting implications there. Again, we're going to talk about team organizations, a team organization, working with your repositories, code shares. So we're going to blend a lot of that in. Finally, I'm going to set aside some time for questions and answers. One thing that I want you to get out of this is I want you to sound smart when you get back to your jobs, your peers, whoever you talk to, meetups. I want you to sound smart.

2. Sharing Experiences and Simplifying Concepts

Short description:

Interesting thing happened to me today, this morning, I was working with one of those car manufacturers, a team that I'm helping there. We had certain issues with service site rendering of federated modular federation. But that's only issues that happen with huge, huge sites. I created a PR and inside the PR I just added a few flags that I needed to add to this headless Chrome. I'm going to share a few things, hope you get them back to your job. I'm going to try not to use difficult words. So if you have experience, please try to listen. If you have no experience, if you're not technical, I hope that you're going to be able to digest what we're talking about.

Interesting thing happened to me today, this morning, I was working with one of those car manufacturers, a team that I'm helping there, they said, so we had certain issues with service site rendering of federated modular federation. But that's only issues that happen with huge, huge sites, when you have to run a service rendered tenths of thousands of pages at the same time. And I didn't know how to solve the problem. So I said, you know, I'm going to Google it up. I'm going to find it and I'm going to, you know, put it in. So I created a PR. And inside the PR I just added a few flags that I needed to add to this headless Chrome. And they said, oh, I don't know how we get to be so smart. How did you find all those flags? And I said, I'm going to Google it up. So I wasn't smart. I just Googled it up. So this is our time of sharing, you know, it's not googling, but I'm going to share a few things, hope you get them back to your job. Also, I'm going to try not to use difficult words. So you're not going to get smart in a way you're going to use like isomorphic apps, something like that kind of verbiage, I'm going to try to be simple. So if you have experience, like I know some of you have with model iteration, please try to listen. If you have no experience, if you're not technical, I hope that you're going to be able to, this is why I hope you're going to be able to digest what we're talking about.

3. Setting Up the Environment

Short description:

We'll start by setting our working agreement and discussing how to use Zoom, Skype, and Discord for questions and interaction. We'll be working with VS Code, using Live Share to share the environment. If you have any issues with setup, post your questions in Discord and feel free to help each other. Let's get started!

And as we started, I also wanted to set our working agreement. If you have any questions, you can use the Zoom and Skype App. It's a great way to get to know our participants. Zoom has that raise a hand feature, if you have one of the latest versions of Zoom. If you don't, I'm going to, anyway I'm going to try to pause every once in a while to see if there are questions. You can also use discord and type your questions, and at some point I'm going to start. It's time for us, I think, to think about our environment, because I'm going to spend a few minutes on the presentational side and as I do that, feel free to set up your environment.

So, we're going to be working with VS Code. I'm going to be working in code spaces, which gives me the ability to share the whole environment with you. I'm going to use Live Share and this is a good time to be in Discord. I'm going to paste. I'm going to send a message with how you can get access to this stuff. So, if you see the message in Discord, I sent you the answers to the GitHub repository and there's nothing in it yet outside of this presentation, so you can take that presentation home with you. And you have a link to VS Code Live Share. If you click on it, you're going to be able to follow through either in your VS Code or the web. I know some of... not everybody use VS Code but it's still good to use Live Share because you're going to see my code, you're going to see my file system, my terminal, you're going to be able to copy and paste things that I put inside.

All right. I'm going to be accepting you as I see it but I'm still going to go on. If some of you have presentation... I'm sorry. If someone you have problems with setting up your environment for one reason or another, and if you have questions about that, I would really encourage you to post questions in Discord. And because we are a community, if someone else has an answer to someone's questions, feel free to share. I might not be able to do two things at a time, talk and help someone with particular environment settings but if you would be so kind to help those people, that would be fantastic. All right. See, some of you are already in live shares. That's pretty awesome.

4. Introduction to Micro-Furnance

Short description:

Micro-furnance allows organizations to work without pausing for code increments, enabling continuous operation and avoiding the need to rebuild and publish a new version. Micro-friends create a decentralized environment where teams can focus on specific business units and collaborate effectively. Microfrenz is more of an organizational framework than a technology stack, making it easy to learn and adaptable to different types of organizations. There are multiple architectural patterns for microframes, but module federation stands out for its runtime connection of modules and efficient handling of dependencies. Module Federation is based on JavaScript standards and can be used with any framework or no framework at all.

All right. So, what are micro-furnance and why they are really good for us? So, one of the greatest things that I love about micro-furnance is that, especially this labor that we are talking about is that they allow organizations to work with their product in such a way that they do not have to pause for code increments, if I can put it bluntly. So, businesses can continue to operate without having to rebuild and publish a new version, and have that toll of time that slows them down.

So micro-friends are a fantastic ecosystem that helps companies. Micro-friends have been around for, that I know, at least 20 or… Actually, I know of examples that are 21 years old, like IKEA. So, they've been around for a while, they've been helping organizations break down, like in this image of Formula 1. Everybody does their work, they know. This person who changes tires, they know exactly everything about those tires, and that's how they're really efficient about changing tires. And this is what micro-friends are giving us access to. So, those big, scalable apps are really always a collection of features, collections of, as I put it, small pictures that create a big one. It's something like, think locally, act globally. It allows teams, they allow teams to think about what they know best. Do one thing at a time and do it real well. Like in the Formula 1 example. Teams can focus on a single business unit and maintain that. They don't have to maintain everything. And it's great because you don't even have to worry about other pieces of the puzzle because someone else is taking care of that too. So, that's the kind of environment we are trying to create.

So, in a microfinance environment, we are basically decoupling. We are breaking apart a monolith. And from a monolith, we create multiple small decentralized features. And moving forward, I'm usually going to refer to them as feature apps, right? Because features are, to me, signaling something that's very independent to a single business unit. And when I say apps, and we all think of apps as something that's very, very cohesive and it's independent, right? So, in this illustration, for example, you see how a monolith was broken apart to features like landing page authentication, carton checkout. Those are business units that are maintained independently. They, ideally, buy independent teams as well. And those are the things we are creating with MicroPrime and Modulo Federation. We are creating these decentralized business units. As an example, I think a lot of you are going to already know this. Spotify is an example of micro-friends app. And this illustration doesn't show exactly how they do this, but just an illustration. You can see how a team works with just a player, just an audio player. They are focused on that thing. They are focused on codecs, they are focused on interaction between the player and the operating system. Interaction with the player when you are in the car. How Bluetooth works, selecting different available speakers. You can say, I may want to listen to the song of my home theatre. There is a team that works just on that. Another team works on recommendations. There is still one app when we look at it holistically, but it's made out of different components. Today, we are going to see how we can connect those components together.

The great thing about Microfrenz is that they're amazing for teamwork. Teams know exactly what they work with, teams know exactly what their business domain is. When used in an agile environment, those teams can work really well and communicate. You know who to turn to, when there is a problem. So in that way Microfrenz is, again, far more an organizational framework than a technology stack. It's very, very easy to learn Microfrenz as a tech stack. It's a bit more complex to be an architect of such a stack of such a solution, but it's a lot more complex to create an organization that works in such way. I'm saying this because some of you may be working in organizations that might not be exactly up to date with how some of those modern lean agile organizations live and work, and that is okay. That is okay. Some organizations have lots of contractual agreements and lots of processes and what not. And I've seen that. I've seen that with organizations that they needed to... It was a little bit more difficult for them to embrace this change than for more modern types of organizations. But it was a change. It created a better company. So if you are in such a company, again, that's totally okay. It can work. Now for microframes, we have multiple architectural patterns. These are not all but historically, how people use microframes, in addition to modular federation, some people can use frames or iframes. That's a very old technology. So, why not? You can connect frames and show different parts of a system. Like a menu can be one frame. It sounds like 1990s, a lot, but as I said, they're not new. Service side includes is something that has been around for a while. I believe that that's how Ikea started. There is an alternative to that being Edge side or Cloud includes, where you combine everything in the Cloud. Again, it's possible to do various accommodations with Git repositories like sub-modules, even monorepos. And those are great, those are nice, it's not a problem, but they come with... It's not as beautiful and as easy as it is with module iteration. Third drawbacks. And finally, NPM modules is probably something that people most often say, well, NPM modules are just fine, I can work with NPM modules, and I can import libraries that I host in my custom registry, so that's going to be my... That's going to be how I do my front-ends. And that's totally valid. But the thing is, where module iteration I think is really bringing the benefit, is two things. One is, modules are connected in the whole, right? And the whole unit in the app, at runtime. And that is big, when you don't have to rebuild the app, you just change, you rebuild the feature that you're connected, like the navigation menu. You have to rebuild that, but as a new version is available, it gets introduced into the app automatically. And that allows you to do crazy things, like for example, you can allow a certain subset of users to try beta versions, or you can, if a new version of a feature is, you know, if you run into a bug with a new build, then you can self-heal and replace that federated navigation with the last known good version. And that can be done in your own infrastructure with Module Federation, because it is built at runtime. The other thing that Module Federation does really, really well is dealing with dependencies, and we're going to talk about that. Again, there are other, there are also other, I'm going to say, frameworks, and I really can't speak to many of them, because I have researched a lot. But what I really like about Module Federation is so standards-based. This has such a small, minimal runtime, and it's really based on everything that becomes a standard to the JavaScript community. It's not opinionated. You don't have to worry about the framework. You can use no framework at all. You can use vanilla JavaScript. You can use React. You can use View or Angular or anything else. It just works.

5. Module Federation and Monorepo Setup

Short description:

Module Federation runtime combines knowledge from all deployed features, allowing for efficient handling of dependencies and leveraging updated versions. Let's switch to the project and set up a Monorepo using Lerna and Yarn workspaces. We'll add webpack, Babel Loader, html-webpack-plugin, and other dependencies. This will be our development environment. Next, we'll create the application core, which serves as the motherboard for connecting other pieces.

So this is, I think, where Module Federation really shines. And I'll pretty much introduce you to this slide as I talked so passionately about Module Federation. So as I said, the runtime is beautiful. The runtime, as you're going to see in this example, is built. So when you rebuild the feature app, it's built based on the metadata you give it, based on the content of the feature. But the beautiful thing about runtime is for all the little features that you deploy, the runtime combines the knowledge. So as you introduce new features of the app, the runtime learns from all their features. And now the runtime knows, oh, I have all these new dependencies I need to take care of or have new versions of dependencies that I can now leverage. I can leverage an updated version of flow dash. Because I see two features, one using older, one using newer, I know how to deal with that. That runtime is that kind of tool, because it learns from everything.

OK. And it's about time we started working with code. I'm going to go switch back to all right, if I haven't accepted your invite to live share, feel free to try again. In the meantime, I'm going to switch sharing to this other thing. OK. All right. So this is the project. Again, the GitHub repository that you have, I shared a link to this. You're not going to need it. I'm going to be working in the repository. The first thing first is I really want to use this as PWA. Because when I use PWA, I can, and it's going to come back in a second, as PWA, I can use keyboard shortcuts. So if you guys use code spaces, it really works better when you install it as an app. The thing is you have to install it for every app that you have. All right. So that means I'm going to have to reshare. Okay. And let me see, this is it, right? Good. Okay. Um, you should also have access to this terminal, so feel free to copy and paste everything that you see on screen. I really do see a limited real estate with all the Zoom stuff that I'm going to try to move to other monitors, but still...all right, we have it. Good stuff. All right. So, I'm going to work with, uh, Monorepo. I did say Monorepo can be one of the ways to create a micro-friend environment. But this is not why I'm doing this. I'm using Monorepo only because it's simpler. We can see everything in one environment and we're going to treat it as complete...two completely different projects, but when working with Monorepo, you know, I can share dependencies. We don't have to wait for installations every time, and so on. Okay, so to set up a Monorepo, I'm just going to initialize it. So I'm going to do mpx lerna init, and as I do that, I'm going to try to enlarge the font a little bit for those of you who are watching on screen. Okay, so we have the Monorepo. We get this lerna json and packages. Before I move on, I do have some settings that I want to apply to lerna because I'm using, I'm going to use yarn, and I'm going to use yarn workspaces. Okay, so I don't want to, I want to use yarn.log and not create package log. I only want to use that one thing. So that is, I think that this is okay. All right. And I think to package JSON, okay, because I'm using workspaces. I'm going to add this and, again, I'm going to copy and paste so you don't have to have this ready, people. All right. So workspaces. So this integration between yarn and lerna. Why is workspaces? Because there are going to be, there are going to be some of the development libraries that I just want to share, I want to re-use between packages. Okay. That's a beautiful drawing. So let's add some things. Right. Let's add webpack and all the other stuff that comes with webpack. Webpack-dev-server and webpack-cli. Right. So that's the usual webpack. So we're going to use module federation with that webpack. I need Babel Loader, and with that Babel Core, and I'm also going to be using html webpack html webpack. login. All right. And this is going to be a dev dependency and with w I added to the workspace. Okay, so that means it's going to be a good a yarn. And for those of you who saw it. I wish you told me this is being deployed so GitHub code spaces can also work for your local vs code. Yes. So with workspaces, you can use it in your locally solved vs code. Totally. So feel free to do that. All right. On my side, I installed a bunch of things if you want to. You can just copy and paste this this whole command. Perfect. So you can scroll up, if he's curl up, you're going to be able to see that command that I typed. So you're an add, all the stuff. So we have that. So this is our development environment, right? We have everything we need. Now, we're going to add the first app. The first app is something I like to call the application core. There's always something that is going to be the like the motherboard in a computer, place where you connect other pieces or equipment. And as I said, I usually like to call that app course. So I'm going to use, again, npx-learner and I'm going to create an app core. Okay. So that's going to create a new package for me.

6. Creating an App with JavaScript and Webpack

Short description:

In this part, we create an app using plain JavaScript and Webpack. We set up the necessary files, such as index.js and index.html, and configure Webpack with a simple configuration file. We then add code to render an h1 element with the text 'hello world' and append it to the body. Finally, we run the Webpack dev server to see the result in the browser. We also introduce the concept of a hero, which is a large image or video used as a call to action in a company's digital presence.

Basically new app. Yeah, that's all good. Yes, it's all there. All right. So in packages app core we have that. Right? So we don't have any code, obviously we're going to need to create some files. I usually put things in source. So forgive me for this habit. Index.js, we need a starting point obviously. We have it. And we're also going to need to have index.html. Index.html. All right. So we have two files. We're going to be for this first exercise this is going to be plain JavaScript, okay? No frameworks. It's going to be really vanilla but I'm going to use webpack. So I do have a very simple webpack configuration. Sorry. I need to go into the root. I'm going to add a webpack. And this one I'm going to copy and paste. Okay, webpack config in app core. I'm going to copy and paste because it's much faster than me typing. But I'm going to walk you through this. Okay. I'll collapse terminals so we have more room. It gets really slow when you have so many people on live share. All right. So this is our webpack config. We introduced path from node.js and HTML webpack plugin that we installed as a dev dependency. And then we say, we're going to be working in dev mode. I like cheap model source map because it's very fast. That's good for development. It really gives you the source code. That's almost exactly the same as in your code. I'm not going to be going through debugging I hope. But in case you want to go see things, this is this can help. And it's still going to speed up or rebuild. Target is web, because we are building for the web. Entry is source index JS. This file has nothing in it yet. Outlook public path auto. This is useful when we start using module federation. It makes it easier for module federation to figure out where paths to modules are. This is only like dev server in module federation combination. That's good to have in development. And, finally, rules for JavaScript. I'm not going to be working with JSX, but this is a habit. Now, Babyloader, we're not transpiling Node modules, and HTML plugin means we're going to have index.html. So, it cannot, I mean, it's very simple. And then, in index.html, again, I'm... I'm going to copy and paste this from a sample because we are not here to write a lot of HTML. Right? So, there we go. Feel free to copy and paste this if you are following along, that'd be great. And with our indexJS, let's add some code. All right, so, what I'm going to do here, I'm going to use plain, vanilla JavaScript to do nothing else but create a tag, right? I'm going to actually copy this again, so it's much faster. We save us some time. I really appreciate the Q&A part of this workshop. So, we're going to basically just render an h1 element. We're going to type hello world, and we're going to append that to the body. As simple as that. But again, because I use webpack, sure, this would run without webpack, but we are working with webpack today. I'm going to need to run this webpack, right? So, inside of scripts, I need to do, I like to use server, so let me please start. So, this is going to be webpack dev server. And if we ever need build, this is going to be just webpack, right? So, this is it. Do you want to see it? Let's go and see it. Okay, back in terminal, I'm going to go packages, and then app core, CD to that. And I'm going to yarn serve. And then let's see if this works. Okay, so port 8080 is available. I'm going to go to ports, make this public Port Visibility in Public. Now you can see that, too. And I'm going to copy this and paste this. What you're going to notice in this query, we have the URL. What you're going to notice is that we used that. There is a port number 8080. So, you can just reuse the URL and when we share other ports, you're going to be able to just change that. And I need to switch to the appropriate appropriate browser I have a lot here and again, let's zoom. Let me share that with you because you don't see the other browser. Give me a second, but I hope you were able to see this in your own browser. Okay, cool. This is it. Hello, world, we have this H1 tag. It's coming from our port 8080. Good job. So we create an app. It's not even, this is not Model Federation yet, but that's okay, we created an app that's using Webpack and why not, we create another app. So this is the app core and now I'm going to add something else and usually what I know, people like to do in their digital presence, they like to add a hero. If you don't know what a hero is, let's try one. So hero is this giant image or video that shows something that's very important for this company to use as call to action, right? So I'm not going to create a video, I'm just gonna name it.

7. Creating Hero App and Using Module Federation

Short description:

Let's create a new app called hero by copying AppCore and updating the package.json. We need to change the module iteration, root app example to hero. We also modify the render function to use h2 and display 'hello world, I feel heroic' text. To run the app, we create a new terminal and use the yarn hero command. We can now access the app at port 8081. Now, let's use module federation. In the webpack-config file, we add the module federation plugin and give it a name. We also specify the file to expose and its name. We repeat the same process for the application core webpack config, but this time, we don't expose anything. Instead, we define the remote module we want to use, naming it hero locally and hero on the remote. The reason both microfrontends use the name 'core' is because the webpack-config file is in the app core folder and the name is 'core'.

There's there's certain positivity around heroes. So let's create a new app, let's create an app called hero. Okay, I'm copying AppCore, and you'd have to create a new one, but it's okay if you copy. I'm gonna call it hero. Because we copied, we need to make sure that we go to package JSON and name it hero, just this, right? The name is here, and that's important for Lerna because Lerna identifies apps by name, not folder. Webpack config is the same. Everything is the same, we're gonna change. Well, we're gonna change this module iteration, root app example, this is not root app example, this is hero. This is hero, okay. That's the title so it's easier for us to identify tabs. Because I copied and we have render hero. Render hello, I'm gonna just go render. We have create element h1, I'm gonna create h2. And we have hello world, I feel heroic, cool, exclamation. And a pen child so it's kind of the same thing. We can run it, right, we already have this dev server so we need to create a new one. This is a new terminal. There is a little hack that I like to do so I don't have to die, when I use learner so I don't have to dive into each package, right? If I go to package.json, I'm gonna create shortcuts for these. And I have these shortcuts available so I can copy and paste, you can copy and paste too. So inside the root package.json I created two new scripts. One is for, the other one is hero. The first, they basically do this, you are in workspace, so find a workspace that's called app core and serve it. So means runs serve command. So that's the one in package.json, right? In package.json, we have serve. So that's what we are doing. And here are the same thing. So I saved this, I think. And if I do yarn, so I'm in root, right? If I do yarn hero, it didn't do anything. Oh because I'm in app core. Sorry, not in root, now I'm root. Yarn hero, there you go. So this one is 8081. We're gonna try to maintain port 8080 and 8081 so we can have know where things are. Now you're not gonna be able to see it until I mark this public, all right? Now you can use the same URL, just change 8080 to 8081 like here. And we see, I feel heroic. Okay, so we now have two apps. And now comes the, hopefully the new part. That now comes to part where we go ahead and use module federation for this, let's see. Okay, we are this. So for this, I'm going to go to webpack-config of each of these, right? I'm going to go to Hero first. This is the webpack-config. To activate module federation, now I know this is available as a thousand readme's and documentation of module federation. So basically this is it. You just require webpack.container because module federation plugin is part of webpack's container. And when we import it, we just add a new plugin. New, NRE new module federation plugin. All right, so we have the AI that's trying to suggest that we put a name. Yes, so we're going to give it a name. I'm going to get a name and I'm not going to name it app core, I'm going to name it core. It's a good practice to name your federated module or I'm going to say your feature app. It's a good habit to name it because it's identifier. It's important that this name is something that is readable to JavaScript, okay? Because the way it gets injected into page unless we change things around is basically basically the script tag that is getting injected will have a variable called var core equals to a self-calling function. So basically if you want to do something that's non-JavaScript like this, this is going to break. But if you wanted to hack it and do this, this is not going to work unless you define core first but you can actually type JavaScript in this name which could be, it's a hack but it could be interesting in certain scenarios. All right, we don't need to work with library. We just needed to give it a name. Now we instantiated marzl-federation. When we give name, that is called a library. Now we created a new library called core. Library is like, it's like npm package, right? It's a name for something that is going to contain some sub-modules. So core, and I need to tell marzl-federation what it is that I'm making accessible to other apps. Need to declare what it is that other apps can use from this one. And that's called exposes. I'm going to expose something. So I'm gonna, well, I'm gonna give it a name. I'm gonna give a name later, but I'm gonna point it to source index.js. Okay, so that's easy to understand, right? Index.js file is going to be exposed, but under which name? Because we were working with vanilla JavaScript, I'm gonna call it vanilla, though I need to prefix it with dot slash. Okay, because you're gonna see why, because we can expose multiple parts, multiple files, multiple modules, and we access them through when we import, right? We're gonna import them as import core-vanilla, right? Right? Alright, this is, well, if you've imported something from core-vanilla, right? This is how it's gonna work. This is why it's dot slash vanilla. Okay. So we signaled what it is that we are exposing, and now we are going to basically repeat the same thing. Let me copy this, paste it as application core webpack config. So I'm copying the import, and I'm copying this whole block. New module iteration plugin. Ah, no, I'm gonna type it. New module iteration plugin. Closing it, so name. I was gonna ask, what is the name, but AI doesn't make it fun. So we're not going to expose anything. We can, we don't need to. We can expose everything and anything, but at this point we don't need to expose. Now we are in this place, we can define what it is that we are consuming from remote. Okay, so we're gonna say there is a remote, there is the remote module that we wanna use. Okay, the remote module is going to be named. I'm gonna give it a name, something that I know of. So we can trust this auto completion of hero hero, we can totally do this. There is a remote that's called the hero. I'm gonna name it hero locally, and it's named hero on the remote. But there is this one little cool little trick. So the question is why do both microfrontends use the name, core? Let me see, are they? So webpack-config is in the app core, the name is core.

8. Configuring Remote Module and Importing Functions

Short description:

In this part, we configure the webpack-config file to define the remote module. We specify the URL and port for the remote module, as well as the name of the meta file. We also import the render function from the remote module and use it in our application core. Additionally, we learn about the importance of dynamically importing the first module and the performance implications of asynchronous loading. Finally, we ensure that the dev server ports are public and observe the successful rendering of the Hero module.

The webpack-config below, oh, you're right, thank you. This is not core, this is hero. Thank you, Lars. So this one is hero. The one above is core, good catch. Alright, now, how I define remote. Technically there are, well, there are several ways of how I define where remote is. There is one thing that is really cool that I like to use when we get started. In production, I think there's not much value but I'm gonna show you later why. Though when we name it hero at, okay, and now at what? I'm going to copy this URL. Hero at and then this whole address, port 8081 because hero is on port 8081 slash 8081. Now there is something that is called, you know like index.html is very important index.html shows links to all the JavaScript files styles and so on. It's kind of like a meta file. There is also a meta file for these federated modules. By default, the name is going to be the same as the name of the module, hero.js. We can change this in a configuration. I personally prefer, prefer to call it remote.js to have a consistent name. But by default, unless we changed anything, it's going to be called hero because this name is hero. Okay. Hero.js. When I put it like this, then I'm letting Webpack figure it out. Okay. So the time has come for me to reload because we have new Webpack and fix, and this one is wrong. That's totally okay. What is wrong about this? Remote's plural. Okay. And let's restart this one. It's important. When we work with a Webpack Dev Server, it's important that we launch them in a certain order because I haven't defined the dev server config, ports are being assigned automatically. So I have to restart the left-hand side first so that it's always port 88, and once that has taken up port 88, then I restart the second one so that second one is 881. Otherwise I would have to change this Azure every once in a while. Okay, I restarted so let's see if it works. This is Hero, Hero maybe will work. It doesn't show much. All right, I didn't make things, I didn't make ports, ports for private. Okay, this is why it authenticated. Okay these work but nothing is happening yet. Right? What I didn't do, I didn't import. So the next thing I'm gonna do, I'm gonna go to the app core, right? I define my Webpack settings, Webpack knows that there is a Hero library that's not in Node modules, it exists in this remote location. So when I use it, when I consume it, it's gonna know where to pick it up from. Okay, so we have render hello. Now we are going to pick it up from Hero. And in Hero is called Render. Now, there's one thing that I didn't do. How am I going to import the render function if I never exported it, right? So I am going to do export default render. Okay, I wanna make sure that I export it as a default export. So it's not named, it should be the default. Going back here. And I think I already showed you this. I import render, I'm gonna call the render hero because it's the default export. From, okay, hero slash, slash, can anyone offer slash what? I'm gonna put it here. Okay hero slash vanilla. It's a capital V, it doesn't have to be. I probably wouldn't put a capital but we do this, render a hero. So I'm gonna put it right under this one, render hello then render hero. Okay, now let's see if this is going to work. I'm going to reload and no, it didn't work. There is something that is preventing me from loading. And this gotcha is important. If you have already worked with Webpack module Federation, you probably know what it is. If you have never worked with it, this is important to mention. When you start with your federated module, the first module has to import dynamically. This is how we do it and then I'm gonna explain why. I'm gonna copy index.js and paste. The original one is gonna become vanilla, I call this vanilla. It's gonna become vanilla. And then the first one, index.js, I'm gonna delete this. Let's close this so it's not confusing. The starting point, the entry point has to import it, dynamically. This is not a static import, this is dynamic import, which works asynchronously. And the reason why it's important is because we have to give Webpack time to figure out the runtime, to figure out where modules exist. So we say, we tell Webpack, hey, load the runtime, figure out where dependencies are, figure out where remote modules are. So this is that first step. If you're worried about a performance penalty of starting your app asynchronously, I measured a huge, that site that has tens of thousands of pages and has several dozens of features scaffolded from a CMS on the page. And it takes about 150 milliseconds to start the rendering. So it's very fast, right? It's really 150 milliseconds for a huge site. It's very fast. And it's not on my computer, it's on a computer that measures performance that's a low spec computer. So this is not going to hurt your application negatively. It's actually very important. All right, this is the application core. I think I can reload now, okay, this works. So let's compare this, give me a second. Before I do that, I know it's not fair that these ports are private, they should be public. Okay, every time I restart the dev server, I have to do this again. So they're now public and when I restart, I get the same thing, right? When I restart Hero, I get the same thing. So what happened here? So first thing happens, you see, I feel Heroic happens twice. It looks like a glitch. But it remembers that dynamic import. Module Federation to Runtime said, okay, I have a remote called Hero.

9. Loading and Configuring Scripts

Short description:

I'm going to load it because the rest of the app depends on it. It's a script tag with the source 'vanilla' from 8080 and 'index' from 8081. When executed, the function renders 'I feel heroic'. In Webpack, I replace 'vanilla' with 'expose' to merge runtimes and dependencies. Feel free to ask questions.

I'm going to load it because the rest of the app depends on it. So it's a script tag and it's probably worth showing this not as source, but as probably elements. So probably not in here. Anyway, it's a script tag like you see this, Source vanilla, that comes from 8080 and Source index comes from 8081. If I preview it, we see a little bit of the runtime and then we see our text. It says function render. We declare the function, but we also executed the function. When we executed the function, it drew this first, I feel heroic. This is why we see it twice, because we executed the function the first time, and then we executed the second time. If I go back to code, we have render hero, but we also executed the same function from within the hero component. Nonetheless, I should do the same exercise here. The same rename like indexation is vanilla JavaScript. This is going to break the app for a second, and I need to use this import for this to really work properly. But that's not it, in Webpack, I need to change vanilla, it's no longer going to point to this index, because it's not where my business logic is. My business logic is in vanilla JavaScript right here. I think I need to move this up here. In Webpack, I'm going to replace this with this expose, I'm going to explain with vanilla. Now we have things in the order, now the runtimes are being merged together to understand each other's dependencies. This should hopefully work. Well, I would need to restart this Dev server. Absolutely. I'm going to pause for a second. I know I'm going fast, mostly in the interest of time. But this is a good time to tell me if you have any questions.

10. Core as Wrapper and Feature

Short description:

In this scenario, a core can be both a wrapper application and a feature. It can serve as a container for other applications, such as a menu app that nests menu items. However, it's important to consider the granularity of features and focus on business value. Too much granularity can make maintenance difficult as the application grows. Instead, teams can work on authentication or other business-focused features that have value and expertise.

No. Okay. I'll go. Very quick question. Yeah. In this scenario, is a core supposed to be the wrapper application or both applications are, let's say, siblings? It's not clear to me if one application is the container and the other one is a content or they are kind of sibling applications? Well, you can do both, right? So, obviously we create a circular dependency if you have core imports hero and a hero imports core. But the beauty- It's a great question because the beautiful thing is that we use core as a container, but core can also be a feature. For example, I'm gonna give you a very simple example that I hope you never use in real life. For example, menu. I'm using this one because it's a simple thing. You can have a feature app called menu and then each menu item can be its own feature app. So they can nest. So a menu nests menu item, but then you have a sidebar that nests the menu and then you have your application core that nests sidebar. Right. You can have it to that depth. Now, the reason why I said, I hope you never use that is about something that I want to talk about after we do the work the exercises, but I'm gonna still bring it up now. I hope you don't do that because there is a clear line. No, there's a very blurred line that we need to clear up. And that is what makes a Federated Module, what makes the feature, right? Is it a component? Is it going to be a menu item? Or is it gonna, how large it has to be? That is a very important problem to solve because, well, my take is it has to be a business unit. Menu item is not valuable as a business unit. A menu could be valuable, but we don't wanna get too granular. When you get too granular and you have this high level of granularity and then you have to maintain the peninsula, it becomes very, very difficult to maintain. It's not gonna hurt you if you work on this now and if you have already done it. It's probably not gonna hurt you for the first year, but as the application grows, it is gonna become exponentially more difficult if you have too granular of a structure, but if you focus on business value, if you have a team that works on authentication, a login screen or user preferences, it's not too small, it's not too big, it has business value. There's a team that has expertise in authentication. This team is a bunch of security professionals that know how to write beautiful UIs and know how to write, I don't know, microservices in AWS, and they are experts for authentication. Now that is a great example of a feature that can be federated.

11. Adding React as a View Rendering Library

Short description:

We have a working example of adding React as a view rendering library. We add the necessary dependencies and configure Babel loader with the Babel preset React. We also add React and React DOM as actual dependencies in the respective package.json files. Finally, we create the app.js file in the component folder and define a simple React app.

Okay. It failed only because GitHub didn't propagate it yet, but now it works fine. We have a working example, people. Okay. I am sorry, if I'm going too fast. I would love to go through a lot of things with you. The good thing is this workshop is recorded. So once it's published, you can always rewind back, and see what we went through. Now let's, you know, let's do this. Let's try to, there's probably stuff that I shouldn't check in, I think it worked through my Gitignore, but that's okay. That's example one. I think this is gonna be good enough. Example one, we have it. I'm gonna save it, push it. Alright. Class. If you go to GitHub, you have this whole code now checked in. So you can check it out and work with it. Okay. So our next step is going to be adding dependencies. And the first dependency that I want to add, I can easily stop this server because we're not gonna need it. Sorry. So the first thing that I want to add is I'm going to replace this vanilla JavaScript with a layout, not layout, with view rendering library. I'm going to use React, okay? If you have used React, this is gonna be an interesting exercise. If you're not the React user, it's going to be very, very simple. I hope that you can follow along and you can take away the things that you really would want to know. So to add React, let me see, what do we need? We need, I was just gonna copy and paste some of these dependencies. To, let's clear this. Okay. To the workspace, WD at the end, the workspace and development. There's gonna be Babel preset react. So that means in this Babel loader, Babel loader, I'm gonna be adding configuration and those are gonna be options. You can copy and paste for an interest of time. So in Babel loader, I'm adding options, preset Babel preset React that I just added. Okay. With options, runtime automatic. So what this means is this allows us, me and us to be lazy when we use runtime automatic. It allows us to not have to type import React from React. This is gonna create that GSX runtime automatically. Okay. We also need this. So this is the heroes WebPack. We're also gonna add this to course WebPack. There we go. So we have the same settings in both apps. I'm also going to add React and React DOM. Now, interestingly enough I use Yarn for everything so far. But now I'm going to introduce dependencies. So those are dev dependencies are common, right? We don't care. We don't care about building with those dependencies, but we care about actual dependence. Non-dev dependencies, actual dependencies. React and React DOM are actual dependencies. So we need to add them in the respective package json, right? Right now, we don't have any dependencies, so we need to add them here. To do that, I'm not going to use Yarn and add. I'm going to use Lerna. Lerna is going to help me add the right dependencies to the right package. So I'm going to Lerna add. I think I'm going to use npx lernad. So Lernad react to packages star. So to all packages, okay. npx lernad react to all packages. Nice, almost nice. Okay. And React DOM. All right. What do we get out of here? I'm going to wait for it to finish. Linking, cool. So we have here package JSON. We have dependencies. React and React DOM. They're both the latest dependencies. Okay. Let's close this. Both latest dependencies. And they are in both packages. Both the same version too. Okay. So, now, we're going to be adding, let me see. In the core app, let's add component folder, right, because this is where we're going to put the React components. And I'm going to create a new file, I'm going to name it app.js. Cool. We have app.js. And it's simple. I'm going to, I have it ready so I can just put it, right. I created an app. Again, I didn't have to do import React from React. Hello world, this is the React app. Perfect. And we export it. Now we're going to, so this is where the application starts.

12. Bootstraping React and Using Cloud Storage

Short description:

We need to bootstrap React by creating a new file called bootstrap.js. We import React and create the root. In index.js, we replace the import of vanilla with bootstrap. We can still expose Vanilla even if it's not used in the app. In Hiro, we do the same process, creating a new component called Hiro and importing it. We have two apps now. We reload both and they are available. In a production environment, the core and Vanilla can be running on separate servers. Using Cloud Storage like S3 for static files is recommended.

Usually in the React tabs, we have index.js and we have app.js, right. But we also need to bootstrap React. We need to create the React app associated with the root node. And for that, I'm going to create a new file, right. So vanilla is reserved for our vanilla JavaScript. I'm going to keep it. I'm no longer going to touch this. We're going to forget about vanilla. But we have this index.js that imports vanilla, right. So let's add another module. I'm going to call it bootstrap. Okay and this is where I'm going to bootstrap React. You'll see why this is important. Also, interesting, right. So just copying some of that React stuff. Okay. So we import React this time, and create the root. Probably didn't even have to import React in this example, but that's okay. So we have, we import React for app component from app components, and that's cool. And in index.js I'm going to replace this, right, bootstrap. Now notice one thing. I am, well this is the core, but I can still expose Vanilla even though it's not referenced in the app. I can create new modules and explore them although they're not used in the app. And that is very powerful. Well, you'll see that a little bit as we work with Hiro. So I replace this to bootstrap, and let me see if there is anything else that I need to do. I think we have everything just about the same. Okay. I've done that in app.js. Now in Hiro, I think I can do the same thing. We have bootstrap. I'm going to just copy it. Okay, copy and paste, it's now copied. In index, I'm going to use bootstrap. Okay. The same process. Same procedure. Probably going to need new folder called components. Okay. And I'm going to create a new component. I'm going to call it Hiro component. A new file. It's lagging. Okay, Hiro.js. Nice. I'm also going to use app.js. I'm going to copy here. App.js. Okay. And inside app.js, well, I'm going to replace this a little bit. This is going to be main. I'm just changing the structure a little bit just because we can. And inside we're going to put Hiro. Okay. Where is Hiro coming from? Well, import. We're going to import it. Import Hiro. Hiro from Hero. There we go. Okay. I think everything from here should work as we expected. We're going to have two apps. Let's give it a try. I don't see a lot of this because I see transcription. I can move it, cool. Yarn serve, and I'm going to restart. This was Yarn Hiro. Okay, fantastic. We have two ports, the same thing. We're public, I wish I had a little robot that could do this for me. Where if someone else knows a shortcut, so that they are always automatically public, that would be fantastic. I'm going to reload both. Waiting, waiting. Sometimes it needs to wake up a little. Okay, let me double check. This should be fine. Okay, it's just the traffic is not going through. Sometimes code spaces can do that, so you're trying to reconnect. Okay, all right, I'm not going to wait for too long. But as you can tell when we load, yeah, they're available, they're forwarding. Oh, let's answer the question. I see some. Thank you, I try to keep the cool if I can. It's also hot here. Congratulations on advancing to level one. In production environment, would the core and Vanilla be running on separate servers? Good question. I'm going to touch on that in a little bit. Because you can build everything with statics, I would advise using Cloud Storage like S3. It's not because I'm an AWS fanboy, you can use whatever other Cloud provider, but here is why it's beautiful, because it's static. S3 is great storage or something like S3 is a great place for static files.

13. Serving and Maintaining Versions

Short description:

You can serve it through CDN. I highly recommend maintaining a similar semantics versioning for features. This allows you to understand version differences and extract useful statistics. Keeping things separated and tracking popularity can provide valuable information. It also facilitates self-healing and easy rollbacks to older versions.

You can serve it through CDN. If you generate statics, I would recommend deploying statics, you do that for CI, obviously, every deployment would get a new version. Just like you maintain libraries semantically, like version 1.2.3, I highly recommend that you maintain a similar semantics versioning for features. This is going to allow you to also understand what batch minor, major version differences are. But if you maintain those deployments, they're going to be very usual, very small, just a few megs of content, but you're going to be able to have to build this whole history of old versions. Then you're going to be able to also extract a lot of useful statistics. If your version of things and if you keep things separated, for example, one bucket per feature, you get amazing statistics. You get to know which features are popular, which feature apps are popular and so on. Now, in a smaller organization and a small product, that's easier to track, but in a large enterprise, enterprise that serves tens of millions of people across the globe, they don't know because content authors scaffold these features through a CMS. Some content authors like to use one version or another or some countries use version 1 and other countries version 2. Who knows what else is happening out there? But your organization can actually track the popularity, the cost of the Cloud. There's just a number of things in terms of information and data gathering that you can get, if you do it that way. Not to mention that it gets a lot easier to do things like that I mentioned earlier, like self-healing. When you run into an issue when a feature is in trouble, there is a bug and then you can easily roll back to a version that's already, an older version that's already deployed. A number of benefits come from that.

14. Implementing Module Federation in Small Projects

Short description:

If you're looking to implement module federation in a small project, I always suggest you to not do that. Don't do that for the cool factor because it's gonna, it has to, there is a toll to using microfront. It's not because model federation is a bad thing, but it's meant for scalability.

So related to above, can I inspect say Spotify and open a player? Probably not. I think, I'll be honest, I knew that. I forgot, I forgot how Spotify does their micro-ferencing. I don't know. If anyone on this call is from Spotify, if you care to share, feel free to. I don't know what kind of technology that they do, or I think they use multi-figuration. So you would not, you'd probably not be able to do that. The key thing about this is that I hope you're seeing is not so much about technology. You're gonna learn these ways of working with Agility and multi-figuration fast. The thing is, is how well you organize teams and how well you organize code solution-wise. Right? And just to be clear, I'm gonna try to help you right away. If you're looking to implement module federation in a small project, I always suggest you to not do that. Don't do that for the cool factor because it's gonna, it has to, there is a toll to using microfront. It's not because model federation is a bad thing, but it's meant for scalability. It's the same thing as deploying to AWS. If you use a lot of services, it becomes difficult to maintain. If you use a PWA, that's easier to maintain. But PWA for a huge site, a PWA for, let's think Amazon, or let's think an actual micro module federation project, Office 365, right? They have this problem. You may know that they've been working for years through the problem of building this huge mono-lith. As soon as they started decoupling using module federation, decoupling parts of the app into smaller features, it became a lot easier for them to maintain, but a lot easier because it's a huge product. If you're working on something very small, it's great to experiment, but I probably in all honesty, I probably wouldn't do that, just because as I said, it's meant for something more complex.

15. Managing Breaking Changes and Federating Modules

Short description:

When managing breaking changes and federating modules, it's important to consider the business code and ensure compatibility between feature apps. Maintaining versioning metadata and following semantic versioning can help address breaking changes. Additionally, data structure compatibility should be maintained internally. We also encounter technical issues with timeouts and port connectivity. Despite these challenges, we create two React apps and export the necessary components. The setup allows for encapsulated development and the injection of development code. The core app is responsible for loading all the necessary steps, while other apps consume the exposed components.

The next question is that, what are how you manage breaking changes and federating modules? When a few modules need to update together, Okay, so let me see. So there are breaking changes between dependencies and breaking changes between feature apps. So I think the question is probably not about dependencies, but the question is about actually the business code. When you have breaking changes inside your features and you wanna figure out those breaking changes and which versions you can better pair, right? When you use feature types. If that's the question, that one is... So the one thing I didn't mention is that again, technically, MyFederation is also raw. It's agnostic, it's agnostic of frameworks. It's agnostic of what you do. And it can really benefit off additional infrastructure. Some kinds of additional infrastructure that you can put to MyFederation can be maintaining your own, I'm gonna say versioning metadata, where you can maintain changes and dependencies. That's good to have. I have implemented for one organization this dynamic log file. That tracks all those compatibilities. The cool thing about that is, when we get to dependencies, the thing is you know, you can know in advance which feature apps work together. So it's like seeing in the future, you know which libraries are going to be used so that you can pick the best versions ahead of the time. But that's advanced level, okay? I don't want to confuse you with that. If we are talking about the easiest way to deal with breaking changes is following semantic versioning. Because semantic versioning is very clear about breaking changes. Major versions have breaking changes. Minor versions have backwards compatibility for breaking changes. And in patches, or again, patches, they should not introduce breaking changes. Um, there are breaking changes in another layer, which is called data. When feature apps use data, they consume a certain data structure. And then it happens that you have a newer version of feature, but older version of data. That's another problem to have. Another thing that can be done by maintaining that internally. Okay. Let's, let's get back to this. Thank you guys for the questions. Medusa is, is great. And you should definitely give it a try. It gets you started. All right. So we have gateway timeout. Timed out. That's totally okay. I don't even know why, why this is timing out. And I hope simple restart is going to help it, which is something that I'm going to do now. But if it doesn't help it, it's okay. We're gonna move on, so we can work on this. I'm glad that you guys are probably also copying this locally and running this locally. Let's double check if anything ishappening here. Compile success, successful now. Okay. Connecting to forward. We see this extra screen because ports are not public again. It's not connected to the port. That's okay, I'm gonna move forward because I wanna get some traction, get some things moving. So what we created are two apps, two React apps. If you're familiar with React, they are very simple. One is app that renders Hello, World. This is React app. The other one is app that nests, okay. And that hero component, has some basic styling that I just put in style tag. I could've put it in any next HTML two. That's totally okay. I'm going to reload this once again because it wanted to work. Okay. All right, it's not doing me justice. It is what it is. Maybe in a little bit it gets fixed. Okay, let's give it a rest. All right. So what do we have here? We have those two apps and what I wanted to do, first thing is also export it. Now we exported Vanilla Hero. I'm also going to export the React library. Okay, Vanilla. And then we're going to have, I'm just going to call it hero, right? No, I'm going to call it something else. Yeah, hero component. Component, okay, and this is going to be source slash components slash hero, right? I use Hero, and here's why. This is a great place for mind mapping, right? The entry point of the app is Index.js. Index.js loads Bootstrap. Bootstrap loads App.js, but we expose Hero. So we export the place where business value starts. Why not App? Because App is useful for us. If we want to load just that hero component like we did in this 8081. In 8081 we loaded just that feature app so that development team can work inside their agnostic feature app. So the development team can use a dev server and work in their little world without anything else, right? So this allows us to have this little enclosed world just for this feature. But when we expose Hero, because this is the thing that is going to be consumed by other apps. Another thing that's great to use here, because, you know, you have one, two, three steps, three modules that are loaded basically only in development. And that means that you can add a bunch of your development modules, development code, anything that you would like to use for development, you can inject in this area. An example, if you have, if your company uses special theming and that theming is always going to be loaded somewhere else because it's reused. Your hero component doesn't need to import theming because theming is going to be given holistically in the rest of the app. But you can also import that theming capability in the app JS. This is not going to be shared, but when you dev serve the app, it's going to be loaded. Theming as an example, another example could be localization or there could be other things as well. So that's where this setup is very useful. Again, the only place where we value all the four steps is in the core. The core is the only app that is going to load all the steps up to app JS, right? And that's where we don't want to have any development environment. Okay, so we have Hero.

16. Importing and Handling Errors

Short description:

We exposed Hero and imported it as a library. We introduced a new React component served from another location. We resolved a bad request error and made the ports public. We discussed handling errors with modification and the flexibility of dynamically declaring remotes. We recommended wrapping injection in an error boundary for React apps. We mentioned routing and the extensive possibilities of module federation configuration options. We observed the network activity and the JavaScript runtime bundle.

I think we exposed Hero. Here, we could also import it because this remote tells us where the module is set. We don't need to do anything here because Hero, sorry, not module, library. Hero is a library. But those exposed modules are something else. They are things that we like to import. So we would just basically go here and because we also know, we can say import Hero, like Hero component from, okay, what? Like, hero slash Hero component. How did we construct that? Hero is the name of the library that we already defined where in webpack config of the core, we named it Hero, okay? And in webpack of the Hero, we exported a Hero component. We exported Hero component and this is why I'm doing slash Hero component. And then here, again, I could be, I could stay true to the naming and I can also name it Hero component and put it right in here. And we just introduced a new React. We introduced a new React component that was served somewhere else. Let's see if we're gonna be any luckier. Let me just double check. So it's running a 8080. There is 8080. It looks all right. It's available, open in browser. Let's see if it works. I'm gonna, okay, bad requests. Oh, okay, this is, bad requests usually come from GitHub itself. And as we see, there are no errors in the dev server. So I'm gonna try again. Okay. Okay, it loads now. I probably have an error some place. Okay, we do have an error. I refuse to execute script. All right, because it's login. There is a redirect. I need to make this public. All right, public. Both ports are public. I can reload. If you guys, oh, it worked. Oh, so beautiful when you do some code and it just worked from the get-go. Here it worked as well. Okay.

Let me take a break to read your questions. And if you have questions, feel free to pop them in the chat. All right, facing the question. If some of the apps will not be available, how can we handle this error with modification? I'm gonna get to that. I'm looking at a time. We have another hour. I think we're gonna make it. So far we showed how we use, not this one, this one. We showed how we use remotes that are statically declared inside Web Configuration. In a little bit, I'm gonna show you how you can do that dynamically. We're gonna delete this remote and we're gonna use our own JavaScript to, we're gonna communicate with Webpack Configuration plugin. We're gonna tell you, hey, Webpack Configuration, there is a remote that I know of and you should use it. And basically that's the end game. That's how you get the flexibility to not worry. That's where the full runtime base, module federation is worthwhile. This is where it shines because if it's statically declared in Configuration that, hey, there is a build sever as required, right? But if we can remove this and make it dynamic, that's gonna be awesome. And I'm gonna show you that. Now, you're gonna have that code to take it home. At least very, very simple version. You also ask about errors. If you're using React, I wanted to say that anyway. I highly recommend wrapping that injection in an error boundary because the thing we react is when an error is out, the whole app crashes. But if it errors out inside a federated module, then if you have an error boundary, you know that something happened, you can decide what to do with it. And if there's nothing you can do about it, then only that feature is going to crash, but the rest of the app is going to work. How do you do with routing with URL state and share? I'm gonna talk about routing, Lars. When we get to, well, after we finish dependency, we're gonna go to communication, I'm gonna mention routes. You can also not explicitly name your exposed components with a dot. Thank you, Ricarta. There is a lot of stuff that a modified variation makes possible. Now there are, I'm forgetting to find my cursor. There are a bunch, there are just a few configuration options. Exposes file name library, run time, blah, blah. Only a few options, but there is so much you can do with it. It's absolutely mind blowing, the combinations of each. So thank you for mentioning this. I think this is useful for everybody else. Feel free to take a look. Ricarta, you rock. Okay. I don't see anyone typing, so let's move on. Oh, yes. So this is where I was. So we have this app. I'm gonna reload it because I wanna watch network. What's happening in the network? Let's take a look. So first of all, ws, this is a WebSocket for the Dev Server. We don't need to worry about that. This is the HTML page. Oops, didn't mean to double-click. The main bundle React2's back, we don't care about that and hero. But the thing is, this is the JavaScript runtime. In main.js, this is a large bundle.

17. Sharing React and React DOM

Short description:

We want our app to only use one React instance. We tell ReactDOM and module Federation about the shared libraries. In semantic versioning, we can lock the version strictly or allow minor increments. We are sharing React 18.1.0 and scoping it with a major version, but allowing flexibility for minor and patch versions. The same applies to React DOM.

And it's large because the whole React is in here. React is here and react is here. So each app bundles its own React and ReactDOM. We don't want that. We really don't want that. What we want is, we want our app holistically to only use one React. First of all, you cannot be serious about having two React instances in an app. It's impossible. Usually you don't want it. So to fix this, we are going to tell ReactDOM we're gonna tell module Federation that we have certain shares, right? So we have remotes, but we also have shared libraries. Okay, let's see. What's shared? So first thing is absolutely React is auto-completion recommends. And for React, you're given some configurations. I don't have these configurations. Again, I could show you step-by-step and show you how we don't use configuration, but I'm gonna skip that step. I'm gonna get right to the juice. So required version is 18.1.0, right? I think that's what we have in package.json. 18.1.0. Now, notice this. In semantic versioning, we can do a strict version and say I require 18.1.0. That means this is the version I wanna have, and that's it. I don't wanna have any other. Then you can do this. This is going to lock it to the minor version. So what works is 18.1.0, 18.1.1, and any other batch increment is okay. Or we can say any minor increment is okay. So that means 18.1.0, 18.1.1, but also 18.2, 18.5, 18.10, 18.1 thousand. Anything that's within major version 18 is going to be accepted as a valid version so long it is no less than 18.1.0. So 18.0.0 is not suitable. So minimum is 18.1 and anything above within 18. So that's, in short, how semantic versioning works. So we are telling the runtime that we are sharing React 18.1.0. I use the same, see 18.1.0, the same sign so that I'm fixing, that I'm keeping it flexible to, I'm scoping it with a major version, but minor and pass are flexible. The same thing goes with React DOM.

18. React as a Singleton

Short description:

React is a Singleton because it receives all the components and renders a single version of the application in memory. It needs the whole tree and cannot update a part of the tree with a different version of React. Other libraries like Style Components also need to be singletons to track dependencies and ensure data sharing. Libraries like Date functions can be loaded in multiple versions, but once a singleton version is loaded, the runtime will not load the other versions. It is important to have singletons for libraries that work with shared data.

Okay. So guys, this is where I'm speeding it up, speeding it up a little bit in the interest of time. I love your questions. I hope you're gonna have a ton more questions. That's a lot more fun I hope. So we have this in webpack-config, the other one. This is hero, right? We have the same thing. We need to tell this as well that we are sharing these libraries. And if I reload again, I'm reloading again, ports. I tried documentation. And it didn't show how I can keep ports. It shows how I can always map boards, but not how can keep in public. That's probably worth mentioning to GitHub. Okay, I'm reloading. Okay, see it's different, right? So now we have Vendor's Node Modules React Index.js, okay? Where is this coming from? Let's see. This is coming from port 8081. Now let's see React DOM. What's the port 8081? This is very cool. Let me see what this is. The Vendor's Node Modules. Oh, this is the JS runtime. And that comes from 8080. So, we have two runtimes, but we could share that one too. Okay? But let's focus on React and React DOM. What this means basically, is that now both features are using a single React DOM. And it's not even using the one from the core. It's using the one from the hero. Why? If you remember when we first had that first example, when we had that render function, it rendered hero, and then core, and then hero again. That's because hero was actually imported first. But, the runtime is smart enough. There's a lot going on under there. There's a whole registry that the runtime is mapping with all the dependencies. And we can trust the runtime, we believe it's really good at it, to pick the best version possible. If we had 10 feature apps with 10 different versions, the runtime would choose the best version for us. So, we can test that. So, if we install, I'm gonna try to not install. This is hero. This is hero. So, if I say, my required version is 1800, and it's fixed, what is going to happen? I'm gonna restart. Yarn hero. Okay. Ports, I need to re-enable that. See, so now I have a little bit of a conflict, right? One version. One app requires 1810. The other one requires 1800. And it's a fixed version. Okay. So what is happening here? Which one is winning? 8081 again, because, hey we are, well, we know it's 8081 because it's in package.json. But what I wanted to show, is as soon as we have a conflict, it's going to find the best version. And it's going to pick, once Hero has an older version, I need to install it too. Once Hero has older version, the runtime is going to say, oh, semantically core has a better version. So I'm going to not load it from Hero, I'm going to load it from a different place. And this is what us doing this dynamic import. This is what this dynamic import is helping us with. It lets runtime to figure out the registry of versions. Now I have scripted a bunch of different variations of how we work with, how we test it, how we test a version conflicts and how we see how runtime uses that. But this is a great thing. Yes, that's right. I also need to have the big package ASAN. This is an actually loaded library. The great thing is you can test that for your homework. But so what I wanted to get to is React is very special. What I mentioned earlier there are basically multiple types of dependencies. And this React can only be on a page as a single instance. Because if you think of it, React receives all the components and renders a single version of the application in memory. And for that only is React and React DOM that working in cooperation to work with the whole tree. But it needs the whole tree. You cannot update a part of the tree with a different version of React. So with that said, because we only have one version of React, we are going to have to say React is a Singleton. So that tells runtime, that tells runtime that whichever the version is the best when we started because we can load things dynamically. I can never accept a different version. I can only always have a single version. Why, because if we have a different type of dependencies, like LowDash, like Ionic, like Date functions, right? If we have different types of dependencies, these dependencies can be loaded in multiple versions. So, Date functions, in version... If you have two major versions, version 1 and version 2, or for example, Date functions, they're gonna be loaded together. They're gonna be same box, their memories are not gonna collide, but they're gonna be loaded together because one app needs version 1, the other app needs version 2. And because we say it requires version, that's how we know. But as soon as we say a singleton in one version was loaded, the runtime is gonna say, no, I'm not gonna load the other version. I can only have one. React is an example of such a library, but also libraries like, Style Components. Because Style Components always has one provider that keeps the theming and it kind of works with all those CSS in memory and all that stuff. So, it can only be a... It tracks all dependencies and to be honest, I don't even know the internals, but Style Components is a neural library that has to be a single ton router. Because technically, some versions of routers can be instantiated multiple times so long you have the same... Like in ReactR is history instance. But in essence, you should have at least that one... That history should be a single time. If possible, the whole react router, because it's not just if you can have multiple versions on a page, it's important that they can share data. If you're in module in two versions, basically what you get is two closures, two separate memory allocations. So you don't wanna, you need to be able to manage that.

19. Sharing Data and Controlling Communication

Short description:

In React, you need to share context and context needs to be within the same memory allocation. It's important to know your Singleton and which libraries should be loaded only once. There are limits to our freedom when it comes to using different frameworks in the same application. Module Federation with MicroFrontends is a great investment for future migrations. It allows you to update features gradually and get feedback early on. When working with micro-frontends scattered through various frames and iFrames, communication between frames can be challenging due to content security policies. It's important to find a way to share memory and make sure that some kind of state is accessible from across frames.

They need to be able to share data. So if they share data, they're okay. But, that's what usually a Singleton does not allow multiple versions because multiple versions means they don't share data. In React, you need to share context and context needs to be within the same memory allocation. Now, I know I'm getting a little bit too deep into this but it's very important to know your Singleton and which libraries should be loaded only once. Sierra boundaries, okay. I'm taking a breather to read the comments and questions. If the hero instance is not running the core app also does not show hello world text. And Lars was right. This is where we talk about error boundaries. So it's not running, meaning you get an error whether it's a 404 or 500 whatever is going to show there but you're not going to be able to load that script app. And when you can't load the script app eventually it's going to error out. Nothing's going to work. But if you have an error boundary you can decide what to do with that information that you have an error. Maybe you can point to a different location or just show a special message. And so thank you for asking this question. Can I use another library flavor for example, Angular in another module. A while ago, I was hosted in a podcast and I think majority of the podcast was about that because I felt it was difficult to grab. So if people say, oh, it's micro-freudens, they give me that it's democracy or it's democratized the development. I can do whatever I want. I can introduce my dependencies. You can introduce dependencies, the best dependencies but there are going to be some contractual agreements. If you use React and Angular, now let's not think about micro-freudens. Let's think about a single page application in an SPA, would you use Angular and React at the same time? And usually people don't do that. But then you can say, but, but why? And should I be free to choose anything I want? And true you should be, but there are limits to our freedom too, right? You can do whatever you wanna do. I don't suggest that, because that's gonna create a huge penalty for the user. How do you share memory? How do you share state between two apps? How do you share navigation state between two apps? It becomes very difficult. Now we get to the place where possibly the question was possibly because of migration. So maybe you wanna migrate react app to Angular or Angular to React. And then when you wanna use strangler pattern, so you migrate sections of the app and that's okay. That can technically, Milo Federation doesn't care what you do because it's always JavaScript. Milo Federation only helps you load the JavaScript from the cloud. And if you can make it work. So in a way that your features are so agnostic, they don't care about that shared state. Or if you wanna manage shared state through a backend or microservices, yeah, that can work, right? You are allowed to do that. But usually those contractual agreements such as the framework, the router. So you use one router, not two routers. And there may be some other contractual agreements that the team may wanna settle on like localization. I mean, yeah, sure, you can have multiple localization libraries. But why load multiple? Usually localization libraries are large. Why load multiple localization libraries if you don't have to? So some of those, I'm gonna say public facing decisions, are I still feel good to be uniform across the solution? Things that should by all means be the choice of a team is how they deploy to the infrastructure. I mean, teams, usual organizations will just go with one cloud. But why not go multi-cloud? Maybe one team wants to deploy to AWS, or AWS wants to deploy, the other team wants to deploy to Google or Azure. Technically that's okay, that should be okay. It'll be totally fine. One team wants to use GitHub or CI or CircleCI or Jenkins. That's totally okay. If you wanna use JS, if you wanna use different, whatever, you know, puppeteer, I don't know different testing side press, different testing setups, that's all happening sort of in isolation. It's not public facing. I think that's great, whatever the team feels most comfortable with. If you wanna use TypeScript, or if you wanna use something else, you don't wanna use TypeScript, that should be the choice of the team. Again, companies may have policies, you may have to adhere to certain policies, but that's the kind of freedom that works well. Now, going wild with different frameworks may actually be counterproductive. Okay, so there's all modules are independent from each other, but you load old framework code. Yeah, exactly. So cool like you use both Angular and React when managing gradual migration with a model of a monolith app. It can be done, but it has to be a good reason. I absolutely agree. Now the thing is, once you went with MicroFrontends, unless you want to migrate to a whole different framework, a whole different architecture, MicroFrontends with Model Federation is a great investment in future migrations. I'll give you a simple example. Moment.js, the library, it's no longer maintained. At some point, they said, oh, we're done. We're not gonna maintain it anymore. It's an old library. There are other alternatives that are smaller, we should use them. So at that point it becomes a little bit more difficult to upgrade Moment, to go from Moment to DateFunction or something else for a big monolith, right? Because you have to just replace a bunch of stuff. If the team was smart and if the team worked with abstractions right away and you create your own abstraction, so you just replace the abstraction, that's great. But most people don't do that. In this example, Module Federation is fantastic because you get to update feature by feature. Your navigation is no longer gonna use Moment. It's gonna use DateFunction. Yes, you're gonna be loading DateFunction and Moment for the time being, but you also get to, the point about string loop pattern is that you start or gradual migration, you start migrating and you start learning about your new migrated app as soon as possible, right? You get feedback, maybe you forgot to migrate a bug fix. Maybe they didn't like the new UI, maybe, you know, who knows? But the ability to get that feedback early on is I think, it's one of the best things that you get from a modular iteration. Okay, Joe has to run through the recall, I don't know if you're still with us, thank you for joining us, Joe. So in the situation that we load the core module in a friendly iFrame, and then Escape to render in the parent window. Okay, so can one dynamically control the window in which hero modules should load by loading extra scripted parent with it? So the question that I think from Sharkey the dog is working with micro-frontends if they are scattered through various frames and iFrames. And that brings us to JavaScript in what you're doing. And usually with JavaScript, it's how your content security policies set up. If you're loading from different domains and across the main policy, it's really how security is set up. Usually it's very much like a network system. Usually I wouldn't count on communicating between frames. There are limits. You can post messages and you can make it work because it is still, at the end of the day, it's still JavaScript. But I don't think I would, unless absolutely necessary, I would do that. If you have an application that uses frames and you want to gradually migrate to micro-friends, then you got to do what you got to do, right? So you can... The only thing is you have to find a way to share memory, to make sure that some kind of state is accessible from across frames. And if you can do that, then you're good. Okay. Amazing questions. Technically we have 30 minutes and a lot to share.

20. Managing Dependencies and Handling Conflicts

Short description:

As we load conflicting dependencies like React, they may be loaded twice in different versions. For example, we used different versions of date functions in the app core and hero components. We demonstrated how to manage dependencies by spreading the packageJSON dependencies and overriding specific settings like React and ReactDOM. It's important to avoid bundling Node.js libraries and consider the backend dependencies in a full-stack application. We also discussed the duplication of date functions due to the conflicting versions and how the runtime handles it by loading both versions separately. Overall, we made significant progress in creating module federation, injecting components, and addressing common dependency issues.

Anyway, what I wanted, the other things I wanted to share with these shares, I'm gonna tell you, because it's faster. As I was gonna do with working with these dependencies, like React and so on, as we load them, as I said, they're gonna, if they are conflicting and they're not singletons, they are going to work, they're gonna be loaded twice, each in a different version. And I have an example for that, actually used date functions. So let me try to introduce that. So I'm gonna create, in one of the components, I'm gonna add a date, right? Something very simple. I'm gonna format some date. And again, I'm gonna copy and paste some of these... Let me see, to the app core, I wanna use data functions 2.1, and to hero, I'm gonna use date functions 2.2. So we have not here, we have technically a conflict of the versions, okay, and I'm gonna create a new component here. I'm gonna name it today, just to show today's date, as simple as that. And to show today's date is gonna be like something like this. So the component is today, whatever today is, today is that day. In any components of hero, I'm gonna say, I'm gonna create a component called birthday, again, it's opportunity to work with time, I'm gonna collapse terminal. Just an opportunity to work with time. And this is definitely not going to be my birthday. Okay, so we have different date from date function, so this is 12-12-2022. To be honest, this date was just auto-completed from this little buddy called Co-Pilot. So, my birthday is in, is going to be in certain number of days, right? This is a difference. Now, let me see. I should probably, also export this one. We have hero component and we also have birthday. Okay, so this is so we can inject it. As for dependencies, I'm going to show you just a small trick. So sometimes we can do this at the top. I'm going to require packageJSON. And then go to shared and simply do this, spread packageJSON dependencies. So what that's going to do, is going to go through packageJSON, is going to look at all the dependencies here and you're gonna see, data functions is version 2.2. And it's just going to copy all the dependencies to share. And I don't need to worry about maintaining this shared list anymore. But if I want to have settings that are outside of just version and name, like here we have Singleton, then I will keep React and ReactDOM, right? They will override those from dependencies. One caveat, some teams, really don't care. Where is dependencies or Dev dependency. If you have this, then you don't want to bundle dependencies that belong to Node.js. Right? So Node.js libraries, you don't want to keep them here because why would you bundle, right? Why would you bundle things that are not useful? You may also run into problems with webpack internals because for example, Path or Fs, you know, those are not HTTP. Those are not available when you target to the web, right? So you don't wanna get into all this stuff. So you wanna maintain your dependencies right. If your application is full stack, which I praise, I wish all applications were like that. Full stack is amazing. In that case, you may have actual dependencies that belong to the backend. So if you have that, then you could just extend this. This is a simple version. We can extend it a little bit and you can build your own resolver where you can either blacklist or you could, if you don't blacklist, you can try to figure out if a dependency is a no dependency. And then you do that and you filter out and you're golden, right? Blacklisting is the easiest thing. Sorry, I had to leave Ricardo. Thank you so much for joining us. Okay, so this is something that we can also paste into a webpack of the hero component, okay? Right here, just doing the same thing, package, JSON at the top. Okay, the same thing. And this is a time when we restart servers. We restart servers, but I think I did everything I wanted to do. We have today, and in the app, obviously, I would probably want to import. Import today from, and this is gonna be today like this, okay? And I also want to import birthday. Okay. So I imported today, that uses local version of date functions, and birthday that uses heroes version, right? So today, hello world, this is a React app. And let me see, today is going to be a div layer. So I'm gonna put today at the top, why not, right? This is not a design class, because I would fail birthday, at the bottom. Oh, is this going to work? Well, it isn't, if I don't change the ports. Okay, code spaces, did you freeze? No, okay. And I need to, oops, yarn. serve, because I'm in packages app core, and yarn 8080, thank you. yarn hero, because I'm in the root. Okay, both aren't running, they are private. It would be so much better if we could keep this always public, okay. It's working, okay. So we have today, it's June the 9th, 2022 and whosever birthday, if you're born on 12December 12th, then your birthday is in 185 days, just so you know, if you know someone else they're six months away from their birthday. So let's take a look at date functions. We have date functions and that's where we have that duplication, see that? So we have date functions and we have date functions twice. So one time is from Port 8081, the other time is from Port 8080. That's because we have a different setup. In one application, we say, date functions till the 2.1. So that means 2.1 in patch versions and nothing else. Whereas this one says 2.2 in all the minor versions that are greater or equal to 2.2. And we have a conflict there. Because we had a conflict, the runtime said, oh, okay, I can work with that. I'm going to load both. They're going to be the same box. They're not going to collide. So today this date is built with one version of the library. This one is built with the other version of the library. And that's how we manage that. Okay. So let's do this. This is example, basically two and three. Let's log this down. Okay, we're done. So, so far, I think we achieved a lot. We were able to create module federation, two apps, simple app. We were able to inject. We were able to work with dependencies. We saw some of the common problems in solutions with dependencies. I think this is, this should be a good amount to get us started.

21. Dynamic Loader and Merging Runtimes

Short description:

I explained the usage of Lerna for managing dependencies and the benefits of using dedicated Git repositories for features and shared code. Next, we'll create a dynamic loader in the core and fix the loading issue. The loader function imports the source using a hook and handles loading and error states. We use suspense to communicate with module iteration and initialize the feature through the script tag. We merge runtimes and registries of dependencies, and finally, return the module as a factory method.

And now, I wanted to wrap up dependencies. As I promised, I wanted to show you how you could load dependencies dynamically. Do we have any questions so far? With what we just covered? Opportunity. Lars. So you said your dependencies are in DevDependencies, but you spread the dependencies. Actually, I spread these dependencies that are Azure dependencies. In DevDependencies, you see, I have them on the workspace level, which is a Webpack, DevServer, and so on. You don't want to share these because these are being executed on this computer, on server, in CI. In the pack, this is not being... You look at the top level of packages. That's what I thought, too. Okay. Again, the reason why I'm using Lerna is, and I hate to confuse you, but I'm using Lerna so that it's easier, so you have everything in one repository, so you don't have to think about multiple repositories. In real life, I would not use Lerna for your project. And the reason is fairly straightforward. As your application grows, your.git repository is gonna be huge, and then you're gonna create PRs, and there are gonna be merge conflicts. And then Lerna is good about sharing. And as a microfinance, yeah, you wanna share a little, but you also wanna own a little. And then if everything is in one repository, all the possible flavors of testing libraries, and runners, and CI scripts, and all that stuff, it gets confusing, right? Because you wanna give that freedom, and if freedom is exercised in a common space, it's confusing. Just like if you had 10 people speaking 10 different languages trying to communicate, but they can't, right? It's not very useful. But the cool thing here is for features, I would use, and I prefer, I always suggest using dedicated Git repositories per feature. And Learn.NET is really good when you decide to create a custom set of libraries for your application. Shared code. The code that you really wanna make available to everyone else, the shared part. So, where you have a special logic for communicating between apps, or where you have special logic for loading translations, or things like that. In some cases even authentication, although that can be dynamic as well. So those are or tracking and tagging, right? Those can be feature apps, but can also be libraries, if they are non-functional, so users still really interact with them. It really depends on how projects and teams use those. I've seen, for example, tracking to be a feature app, so that means I'm a feature app, I'm totally agnostic and I do my thing. I can expose libraries, others can use them, or I can do my own thing, that's a feature app. Or a library is, I'm meant for others to use me and I'm not doing anything automatically. My purpose is for other projects to use me, but they don't have to use me. So that's the difference, so that's why I said, technically this is easy to understand, I think, I hope. Architects and solution architects can have a little bit of a hard time getting things in order, especially for the first time as that experience is being built, but the major improvement and change, and we know how change can be difficult, can be on the organizational level. Okay, I'll stop preaching about that because there is always a story about everything we preach, and this can really get messy. Okay, so we saw that, and as I said, the next step is for us to create a dynamic loader. Now, I'm gonna do that in the core, so we have remotes, I'm just going to comment this out. I'm doing this, so we have some kind of history, so I commented this out, and we probably need to restart the server for this one. Okay, and obviously, it would fail if you're trying, so this is public, private, good, public. All right, it's probably going to fail. No, it is going to fail, because it doesn't know how to load to Hero. So let's work from here, let's fix this. So app is using these two libraries. Yeah, I can no longer use this level of import if I use dynamic loaders, so I'm going to resort to something else. I'm going to create a new component, I'm going to call it loader. I have it ready, guys. I'm not going to be typing it. And trust me when I say it has probably a couple of hundred lines of code. No, almost 100, but this is a simple version. And I'm going to walk you through this so you know what's happening. First of all, let's skip this, let's skip this step. I'm going to talk about that later. So what do we need to do? We need to create a script, right. We need to create a script. It should be a synchronous. And we attach a listener on load. So when it's loaded, we say, we are ready. If there is an error, we say, oh, there was an error. And eventually when we unmount, we can remove the script tag, right? That's just working with script tags. We're gonna be using this loader function. So the loader function does this, uses this hook to import the source. And if we are using development, now in the build step, this block in production, this block would be deleted because Webpack is going to statically know the environment is production, so I can delete this code, tree shaking. But we are working development and we're gonna see loading feature and a fail to load feature if it fails, right? As a helper. We use suspense and that means when we are loaded, we're gonna kick in this function that communicates with module iteration. So that's what I said I was gonna mention later. So this is really not. I don't think you find this in documentation but you can find traces of these, you can find traces of these commands or maybe even very similar functions in various examples online, right? I even think module federation, a GitHub organization that's owned by Zack Jackson I think he may have created something that is too. Anyway, the whole thing is we call these special functions that are only available because webpack registered that our code needs it. You can not call this for console, this is not in global scope. A webpack parses your code and it says, Oh, you need webpack in its sharing, this is a special method. So we say, okay, I'm going to, again, in a sharing there is something called scope. We always use the full scope but you can create additional scopes. I haven't shown you that because I feel that that's mostly not needed. The full scope is just gonna cut it. But if you need to load a shared modules in different namespaces, then you can do that too. Then the default namespaces, obvious default. So we are initializing that feature through this line. And then we say Windows code. So if you remember when I said, we go to a package, sorry. Not package, I meant webpack-config. And we named hero, right? So that means there is going to be an object called window.hero. And that's how it works. That's how we bundle the JavaScript modules. And that is also configurable, if we change that how that library works through config, there is documentation for that. This is definitely out of scope for this intro. But you could totally change how features are bundled. Again, I'm not gonna touch that, but so far just so you know we get that container, now which is the runtime. And then we initialize, right? Webpack share scopes in the default share scope, we initialize that container, that script tag that we received, we say, hey Webpack, so we call the init method of that script and we merge it with that default namespace. So, that's when I said, every remote feature that you load is going to merge runtimes, it merges registries of dependencies, merges in the information that they share as they get introduced. And this is that merging, initializing, right? Finally, we get the module and we return it, it's a factory method.

22. Loading App and Communicating Between Feature Apps

Short description:

This part focuses on loading the app using the Loader component. The Loader has properties like source, library, and mod. The source is the address of the module, the library is named Hero, and the mod is the birthday component. The Hero component is dynamically loaded and imported at runtime. The speaker emphasizes the power of dynamically loading modules and connecting them with a CMS. The section also discusses communication between feature apps using an event bus. The speaker encourages minimizing coupling and highlights the agnostic nature of event listeners. The benefits of using events natively and avoiding excessive library usage are emphasized. The ability to capture events by multiple instances without effort is mentioned. The section concludes with a discussion of the drawbacks of events, such as the potential for missed events if listeners are not yet loaded.

I know this is usually a lot for most people and you can easily just copy this bit, it's going to cut it for most applications. Okay, so, this is the app, now comes the part, how I load it. I'm gonna go back to app, again, Loader, I need that Loader, Loader. I can no longer instantiate today and birthday like this, but I can use Loader. And Loader has some properties like source, library and mod. Okay, let's start with source. Source is going to be, I'm gonna steal that from Webpack config, not this one. This is the source people, this right here, hero.js. So this is the address. And now what else? I have a library. Library, if you remember, is called Hero. It's important that we name things the way they are named, this one. Library is called Hero. And module, I didn't, I use mod, so I don't use module because modules, definitely it is reserved, but it's gonna work okay. But to make it clear to other developers, this is not module.export. This is, I didn't want to confuse anyone with that. So it's not Hero component we used today, right? No, birthday. Okay, so birthday. Yeah. Okay. And it's gonna be.slash birthday. So this is birthday and that replaces this one. Okay. So the birthday stays today because that's local, I imported it here locally. But Hero component, Hero component has to be lower. Hero component, the same source, just the component is... Okay, the same expose that I used before. Okay, it's one of those things. Let's see if this works. It's loading. As it's loading, I'm gonna verify that I indeed have that. Okay, it is running and port is public. But I see, I don't remember if I restarted. It was core, so I'm going to restart it. And I will change to public, in case you are also tracking. Okay. Waiting for, is it waiting for everybody? Does that inconsistency sometimes. Okay, sometimes we have to give it time. But we are again, close to, thank you Michael. I'm glad it worked for you locally. I'm gonna give it time. It looks like, it's still cranking up. Oh, there it is. Oh, there we go. So the way we know it's working is those messages that they wrote, the status messages. You see, you know, loading is a loading feature, loading feature, loading the app, bam, is thrown here. So we just dynamically loaded a module. We loaded something that is stored somewhere statically in the web on the cloud and we imported at runtime. So imagine connecting this with a CMS, like Contentful, if you will, with a CMS and allowing people to scaffold their own app as they wish, passing configuration to each feature. It's really remarkably powerful what you can get out of this. All right. I'm going to pause with code and before I do that, I do owe you this example, two or three then this is four. Okay. Go reload. Okay, I'm going to commit that. Anyway, I want to give you, as I promised, a few more things. Okay. Let me, let me find that screen. Slow down if you need to.

So the thing is, how do we communicate, how do we communicate between apps? And this whole slideshow just is on the GitHub so you can download it as PDF. So how would feature apps communicate between one another? So one approach, a common approach is using the event bus. Before I actually tell you about observables and event bus, I wanna say that the whole thing, the whole point about micro-feelings is that if you can, by all means, do not communicate. It's never gonna happen. You cannot remove communication. But I wanna discourage you from creating coupling, points of coupling. What you did, what you're doing here is you're escaping from the chains of a monolith. You're creating something that's independent. But when you create coupling, you're basically going back to a monolith. You should try not to do that. Communication creates coupling because it creates that dependency. Again, sometimes you have to communicate. Event bus is one of the ways. It's great because it's like you fire an event and someone listens for that event, listens for a trigger. So the cool thing is, it's again, I love when things are agnostic, when they don't care where they are. And listeners are usually agnostic you're going to say, oh, I want to listen to this route change event. And when someone changes route, then I'm going to do one of the thing. I'm going to calculate something and work it out. I'm going to send, I'm going to send a tag to the tag manager or something like this. And that works, that's okay, right? It's beautiful. It basically removes a lot of the kind of dependencies. You don't need special libraries for that because events can be used from the natively. And as you work with MicroVerse, I highly suggest, if you can do something natively, do it natively. You don't need to, you don't always need to use libraries for everything. And as teams go crazy with libraries, it can be, you know, it's still a lot of JavaScript. Another cool thing about events is that they can be captured by multiple instances, and you do that without any effort. Anyone can assign events. You can assign event batches, groups of events you can sign, you can create crazy things like catch all events. You can do crazy things, but there are drawbacks. So what if you want to fire an event but the listener is not yet loaded? The feature that it should listen is late by one millisecond, and it didn't catch that event.

23. Event Firing and Communication Methods

Short description:

When firing an event without a loaded listener, there is uncertainty about whether the event was consumed. Creating a listening system or using services can help, but they introduce dependencies and versioning complexities. Server-side communication has high latency. Shared state with Redux can be viable but creates coupling and versioning challenges. Routing offers a simple solution as a global source of truth, but it has limitations. The observable pattern with minimal communication can bridge shared memory gaps. A store can be created as a simple reference in memory to handle multiple library versions.

So what if you want to fire an event but the listener is not yet loaded? The feature that it should listen is late by one millisecond, and it didn't catch that event. So you're never sure of the event that you're firing was consumed. And that can be a problem or maybe the event was fired multiple times, but then a feature app that wants to know about those events is loaded. And it's never gonna know about the history. Sometimes you wanna know about how that event was triggered from the first instance onwards, and that history is lost, right? You only know little pongs like pong, I'm here, event pong, but you don't know the history of previous pings and pongs. So that can be a problem. You can work around it. You can create a listening system that is going to say, oh, if no one captured me then queue it up. And whenever a feature app that has a listener comes by, then fire it. But that's not, that's far from perfect. That's not gonna cut it for all the purposes because the first one is going to see it, but not consecutive and it can create problems. But I have problems for each one of these. You can use services. There are micro-friends libraries that bank on services heavily. By services I mean basically code functions, right? Can create functions that serve as a communication bridge. That's what I meant when I say for services. And that can be interesting. That can be even cool. You can have teams that solely are solely dedicated to services or services can belong to those teams and own that business unit. Also, the problem is it creates dependencies. There is a dependency to a service. And when there are different versions in fact that creates a little bit of a versioning hell. Right, you can maintain your own versions. You can have service version one, service version two. You can do that. It gets complicated. As your application co-founder, I guarantee services are gonna get complicated. And one of the worst things you want to have is you don't want to have a system that requires people to learn a lot about. As soon as you diverge from the standards, that means from now on, you require additional learning. So when you onboard a person to your team, it's gonna take them two months to understand how your services work, how your services, version one, version two, and other versions work. That becomes a problem. And the services end up, I wish I could tell you a name, but there is this big, big company. It's a huge company in Germany. It's one of the world's largest companies. So they ended up with services. That whole system really takes, at least, I think, the median is two months for a person to get onboarded and to learn about how to use them. It's that complex. I'm not saying that, I'm not trying to scare you away, because services can be very clean and beautiful, but because of that dependency that they're creating, you need to escape from version mismatches, and that can be troublesome. Server-side communication, obviously, I mean, desk, that's clear, right? You maintain something on the server side, you send things, you send communication to, hopefully, your cloud and not a RESTful server, and that's useful. That's useful for things like that question with, what was it? Frames, right? Okay, you just send to a server and communicate back, but because of the latency, it's obviously very laggy, and people are gonna notice. The rule of thumb for latency is, my rule of thumb, is 200 milliseconds. But right now has anywhere from, usual people have 30,000 to about 200,000 receptors in the retina, it takes them about 150 milliseconds for that image to be transferred to the brain, the brain recognizes, parses the image and recognize what it is. So that's why our reaction time is between 150 and 200 milliseconds. We see that something has taken the time if it's over 200 milliseconds. And if you need to communicate to another feature, it takes more than 200 milliseconds, users are gonna notice something is slow, something is happening, right? So that's why the rule of thumb to me is 200 milliseconds. I have a lot of these numbers that came from spending years on learning about psychology, to be honest. I think UI development is a lot of human psychology. Shared state, very viable. I can't tell you how many times I heard, why don't we use Redux? You can use Redux. Redux fixes some of the issues, I mean, it doesn't have to be in the Android State Manager, can fix some of the issues that we talked about earlier. For example, repeatable state, you can see the history, you can see how things changed over time, right? If you end up needing that. Also, Redux, especially Redux, can be lazy loaded. But most of our state managers can be lazy. I'm saying Redux because we basically use React here. It doesn't have to be. Also, Redux is probably one of the simplest state managers, or earliest, something like this. But a lot of people know about it, and you can easily lazy load modules into a state manager. So that's good because you want to lazy load things. You want to load things when they're needed by that feature. However, it's a mix. It creates that coupling. It makes it very, very difficult to work with that versioning. So as you load multiple versions of feature apps, they may anticipate different data structures. If those data structures change between versions, maintaining that in Redux, in Redux you only have one node, one tree node, state tree node, right? You cannot have a versioned state tree, or you could but you have to build that. So creates that coupling, which is where I'm personally not a huge fan, but it obviously fixes some of the things. Now, this leads me to routing. See, all of these have pros and cons. I'm not trying to tell you which one is the best, although routing is the simplest. And there was a question about routing earlier. Routing is global, it's holistic. It's, routing is single source of truth for the entire app. You can pass a state route, still. There is a history component. You can know the path to that endpoint. You can share the point in state to other peoples on other peoples, other people on social networks. You can do that with routing. And out of everything that I mentioned is the least friction or communication. It does require, as I mentioned earlier, histories because it's where information is sort, has to be singleton. You cannot have two versions of those because then you would have basically two libraries managing the same history and that could not end up well. Also you cannot do everything with routing, right? You cannot send requests for a function execution, like, oh, track this event. You could be changing the state, but that's why routing is awkward. It can be awkward to do that. Out of all of these, I think the least friction is routing. And the other option that I kind of like is the observable pattern. But with one caveat, and that means constantly guys do not communicate, and teams try not to communicate too much, right? I also end up to bridge some of the shared memory gap, sometimes I end up creating a very, very simple reference in memory and making that a single time. I usually call that store, kind of shared storage. And that shared storage is not global, it's still module-scoped, but it should never change the version because it should always be very simple, nothing should change, it's always the same reference in memory for JavaScript. That makes it a lot easier to bridge some of those problems that you get when you have multiple versions of libraries, right? Taking a look, okay, no questions so far. Thank you for all the great comments in this record. So I'm gonna move on, we are a little bit over time.

24. MicroFriends and Hybrid Apps

Short description:

MicroFriends enable hot updates for hybrid mobile apps, allowing users to receive fixes without updating through the app store. When working with MicroFriends, think globally but act locally. Consider the interaction of your feature app with the entire system. Avoid creating coupling and strive for backwards compatibility. Use semantic versioning and deploy each version separately. Consider using course headers to prevent opaque responses and ensure caching works properly.

If you can stay on, that's fantastic. If you have to go, it's totally okay. I mentioned this earlier, so I'm not gonna spend too much time on this. Just like in design system, we have atoms and molecules, the organism, templates and pages. Atoms being like a button and molecule being a component that contains multiple atoms, those I think are good for design systems. That's where we say how granular things are to be for microframes. Organism and templates are in atomic design. Organism and templates are the... I feel in my experience are the way to go. Something that is not too simple that has some complexity of some business value. It's very important to have business value. And that's a good separation for when to use microframes. This is a very, very simple, basic architectural diagram that shows again hybrid apps, browsers, desktop, how things can work together in the cloud, right? When you deploy everything... You can deploy everything in the cloud. You can have a content management system that basically works with these features, allows content authors to scaffold features on the page. And every feature has a life cycle on its own. It has a CI, so GitHub repository CI, and deployment on, it has life on its own. The important thing I mentioned, I'm gonna talk a little bit about hybrid. Hybrid apps can work amazingly well. So long it is JavaScript. It has to be interpreted language per application code sort of guidelines. Also, what you can do, you can do amazing things like a bypass, when I say bypass, that was negative, but you heard the App Store guidelines. You can hot update interpreted code like JavaScript so long it's a patch, it doesn't change functionality. So, what you get out of this? You get the ability to ship a mobile app, hybrid mobile app, and you get, when you ship it, you have to bundle everything inside, right? You cannot bundle just the core, you have to bundle everything. And there are strategies that work well for bundling. You don't have to rebuild the whole app, you can create manifest and publish them on CDN. There's so much about MicroFriends. But the cool thing about this, the value behind this is that your users can work with the app, and as they work, they get a hot update, their application gets a fix, without them having to update it through the app store. And so long as it's a patch, per, well, current, at least that I know of, Create an Application Store guidelines, that is okay because it's interpreted language. I'm gonna share a few tips, share a few tips with you. Again, when you work with micro-friends, I said, think globally but act locally. So you focus on your business value, but that holistic perspective, on the whole system is always helpful to have. How is my feature app interacting with the system? What is it that is available and the whole, right? I talked about, mentioned agnostic a lot. Yes, you should be agnostic, that's act locally, but that little thing that sits on your right shoulder as you work, but thinking holistically helps a great deal, especially if your position is within solution architecture and when you have to think about the big picture, right? You gotta, you cannot tune out out of that. Always, always ask, when I do this increment, am I creating coupling? Can I do this better so I don't create coupling? I also talked about deploy features in versus sub-folders, and I think why that's important. And when you deploy a CDN, whatever you wanna deploy, every new version, I highly suggest semantic versioning. There are several libraries that can help you with that. Deploy each, don't overwrite. It's not good to overwrite because you never know which version your clients are using still, right? You wanna append, you wanna create a new folder with new versions, and that can be very helpful. We also mentioned when you inject feature, especially dynamically rather than in their boundaries for self-healing to recover data, so grateful for that question. I will kind of implicitly say, I mean, see if you can communicate through the routes only. By that I mostly mean, yeah, see if you can communicate only throughout. Changes are you not gonna be able to. But again, that goes to trying not to create coupling. When you work on incremental, try to think about backwards compatibility, because as I said, you never know who uses an older version. If you're working in the highest scalable system in a global organization, then maybe there are those content authors, someone you don't know who uses your feature and you don't know which versions they're using. And if there is a collision that you're not backwards compatible, maybe it's gonna break. So thinking about backwards compatibility is useful. And thinking about semantic versioning is also useful. So you know when to use major and minor that could help that creates order in this chaos. Usually for statics, we don't need course headers, obviously, but in this case, I suggest that. The reason is, especially if you host features under their own sub-domain or something. When you load JavaScript from a different sub-domain, that is going to work, it's going to be fine, it's going to load. But cross-domain JavaScript creates an opaque response. So that means it's going to work for safe response. The browser is going to internally try to hide headers and hide some of the content for security. And your cache is going to blow. So in theory, you would have maybe 400 kilobytes of cache, but you end up having 400 megabytes of cache. It's while it's not true that you use 400 megabytes of Java Script with opaque responses, you still go above the cache limits or file storage limits and your browsers can crash, your application may end up not being cached and thus load slower. So if you just use course allow and then asterisk allow, and that's safe enough for statics. You're gonna allow browsers to load that resource in a non-opaque way. Service workers are gonna be able to work with it just fine and caching is gonna work.

QnA

Frequently Asked Questions

Short description:

Can I mix and match JavaScript frameworks? Technically you can, but try not to. Should I use monorepo? Probably not. Microfrontends promote agile implementations and efficient team communication. They allow for granular development and A/B testing. They make application updates faster and more cost-effective. Microfrontends provide valuable insights into feature performance and cost. They enable lazy loading and improve application speed. The concept of feature as a service allows for easy deployment and injection of features at runtime. Caching and preloading enhance performance. Webpack 5 is the industry standard for microfrontends.

All right, Frequently asked questions, I'm just gonna mention what people like to ask, but I think I mentioned some of this. Can I mix and match JavaScript frameworks? We went through that. Technically you can, try not to. If you have a strict organization, I mentioned that too, if it's strict organization that some organizations who just like to prescribe everything, right? Sometimes it's just painful to work in that organization because you want to guess, you want to learn new things, you wanna experiment, you wanna be able to make a mistake, you wanna maybe try to modernize, but it's not possible. It's okay, right? It's okay, you can work with that too. Should I use monorepo? I mentioned that too. Please, probably not. Try not to. Monorepo are good for libraries, but for micro-friends, for feature apps, try to separate them into dedicated repositories.

Now, the following slide is a portion of the slideshow that I have used with business people, because they don't speak the engineering language. It's this segment, and I felt it would be cool if you guys had some of, if you wanted to use some of this information to share with your bosses or clients, so that if you really wanted to work with microfrends and be paid for it, then why not? So one of the things that organization like they have is that microfrends actually do promote agile, when I say organization, I mean, just company, agile implementations. It's the learning curves are very fast because you basically don't need to learn about the whole application. You learn about your business unit, you learn about your navigation or you learn about your authentication, user management, you learn just about that. And if you do what Micro-Module Generation does, if you say standards compliant, it's amazingly fast to get onboarded to a team, offboard and move to another team. Teams communicate much more efficiently because we know which team is responsible for what. And you can create a team-based communication channel and say, hey, team, you know, Burger King. I have a problem with this. You guys figure out who's gonna help me. But I know that this is in your domain and that communication works amazingly well because you make that communication easy, you actually get more communication and that means you get more feedback. And for Agile you really want feedback to get better. So Micro Friends are an organizational change and it promotes Agile. Now as I said, Micro Friends can be small or big as whatever works with your team. As I said, don't go too small, I think that's good advice. But you make it fit to your company. Usually when you start you wanna have people like product manager, designer, architects maybe front-end engineer, you wanna talk to them, you just wanna see, hey, how can we decide what the feature is? Usually you're gonna get to the same point. And sometimes you wanna reiterate through some of the ideas, but you get to the same point. You create that granularity that the works best for your company. So what that means is when your company wants to ship an increment, it ships just that small piece, not the entire app. And it just works. And you know what granularity is also good for? A B testing. When you have a granular app, you can see how incredibly easy it is or even powerful it is to create A B testing to say, oh, for this subset, for a certain subset of users, I wanna use version one of my feature and version two for other, but maybe I wanna use, I wanna say close beta or opt in beta, or I wanna allow people to opt in for new features. This is incredibly important for organizations because they wanna be able to not ruin customer experience. They didn't wanna create, for example, a whole new design too quickly because people maybe got used to the old one. People don't think the same way we think, users don't think the same way people who create the app think. So when we think, oh, this is gonna be better. Maybe they don't welcome it as much. And if we can learn from that, we learn granularly. And if we see, oh, this is not working out, then because it's granular, we get to replace it. You say, oh, this new login window is confusing people. Oh my, let's replace it right away. Let's fix it right away. Let's restore until we figure out a new version, a new way to do that. Again, if your organization has ever gone through a major immigration, it's going to know that it's painful. It's crazy expensive. When we create a MicroFronts infrastructure with architecture, it's really future-proof. It gets a lot easier, for such an application to migrate in the future. It's cheaper. Straightened out pattern is there. It's almost a give it. And not just that, because things are granular. Well, one thing that you get, and you saw this in the last example, is also lazy loading. I mean, you get it by default. And what that means is that applications, or, sorry, users load just enough JavaScript. Just enough for that user interface to be used. They don't need to load JavaScript for features that are not present in the viewport at that point. And that's something you get it out of the box. So applications are also much faster. Over their updates, those can be really big and I kind of talked through that a little bit because not just, you can reiterate, not just you can learn and improve, much faster than with monoliths, you get to fix things much faster. You get to push bug fixes, hot fixes much, much faster. You don't have to rebuild the whole app. You just rebuild a small feature. Push it, it's out. Microfrontends allow us to see really interesting, well, I wanna say dashboard. So information on how, well, how much features costs us to develop? How much they cost us to put in production? How much they cost us in bay width and cycles. If you use backing code, because everything is contained as a feature, right? It's almost name space. You can extract a lot of localized information and learn about performance of each feature. Not just each feature, also each version. It's not just tracking, because we know tracking doesn't work for everybody. People are good at blocking trackers. But this is server-side, and you can track requests, and you get new powerful ways of learning how successful the organization is with features with their increments. Which is really amazing for learning how to get better. Now, the whole concept is something I like to call feature as a service. And we talked about that, where we get to deploy features to a CDN and then inject them at runtime. So, the runtime, the Java runtime is very small, the thing that Webpack produces. And you can really just go crazy with a swarm of features and inject them as they are needed. Basically, as they are rendered on the screen, they get it injected. Also, they are very good at knowing, oh, I have already been injected, so I can reuse existing instance. Oh, caching is amazing. It's very opportunistic to cache these features and even preload features ahead of time. You have all this information that you can use for performance benefits. And we're using Webpack. Webpack 5 is the industry standard. It's not the only bundler that has microfrans, modular federation. Webpack's implementation is really strong. It's tested. I'll be honest, it is the one that I most use. So I'm very familiar with it. I'm familiar with Webpack as it is. But it allows great efficiencies for developers. Is this because they get focused on things that they do best.

Benefits and Considerations of MicroFriends

Short description:

MicroFriends offer automatic code reuse and the ability to share libraries. However, tree-shaking capabilities are lost when using shared libraries. MicroModule Federation has been successfully implemented by numerous large organizations, enabling collaboration among teams and efficient system operation. While MicroFriends have their benefits, it's important to be cautious and not take everything for granted. It's recommended to try MicroFriends in production for highly scalable apps and larger organizations. For smaller applications, it may be more suitable to try it in a prototype. The organization of deployed code can be managed by using versioned folders, ensuring that each version is always available. It's possible to create a system that tracks version numbers and automatically redirects to the latest version. Lambda OnEdge functions can be used to dynamically handle version routing.

They will know their business domain really, really well, and they can be very successful at it. You get Code Reuse. That's how automatic that's all those libraries and all the functionalities that are used. There is a caveat with libraries are automatically used. You lose some of the tree-shaking capabilities because you don't know which part of that library is going to be better app. So the whole libraries are packaged, right? When you use shared libraries, the whole library is packaged, not just a part that was used by that feature. It has to be that because it's shared. You don't know what they're going to use. But automatic Code Reuse is great. If we saw that, we don't need to bundle two versions of React, two versions of Dave functions. It's automatic, it's given to us out of the box. And then again, I mentioned all those beautiful little keywords that you can share. And it's not like this is, I mean it's been around for a couple of years since it was October the 10th, 2020, when the production version was released. But it's been around earlier than that. I have personally brought MicroModule Federation to not all of these companies, but most of these companies, more than half of these companies. And it's something people use. They are successful. These are big organizations. They are capable of running huge, huge systems that are global, that are operated by hundreds, thousands of people. People who create feature apps, who design feature apps. People who use them to create content. People who analyze. People who are business people. And it's really, as I said, it's not... I think we are beyond the point where we are testing the capability. We are at the point where we know, hey, this works. But it's on us. It's on us to see if this is for us. Today, I think what I wanted to do, I wanted to tell you that there are good parts about MicroFriends. There are also things that you should be careful of, right? You shouldn't take everything for granted. You're gonna read a lot of beautiful things about MicroFriends and things like, you can use any library. Theoretically, that's true, but in practice, you gotta be careful. That you don't want to shoot yourself in the foot. That's my point. And so I wanted to bring you the good and the ugly. I don't wanna scare you. I wanna say, it's okay. You should try it. You should try it in production. As I said, I can't tell you exactly what the size threshold is. But for small apps, maybe an overkill. Try it in a prototype. I think MicroFriends are fantastic for highly scalable apps where they're front-end scales technically. Where teams need to scale. When you have either large numbers of teams that gets spun up or down where people come on teams and go out. So those are usually bigger organizations. It works fantastically well for them. And if you have access to that, you know, you can always reach out to me. You can always reach out and say, hey, you know, what do you suggest, how would you go about this? I would love to help. Again, if you have a small application, it's, that's more like, you know, let me try something cool, you can do that. But just don't want you to create something you're gonna need to maintain in the future. Almost the last slide. Any questions so far? Cristian? Yeah, I wrote, I wrote an, what's the name, Discord. So can you elaborate a little bit about versions of folders? Let me see what I'm sharing. I'm sharing this screen. Let me see if I can. Yeah, basically, I mean, it's about, you know, the code, the organization of the code or is it about the routes, which must contain like V1, V2, or maybe both? It's organization of deployed code. And if you remember, in the code, we had that source address. And we said, a hero at an HTTPS, and blah, blah, blah, 8081, slash hero digest, right? You can, what I would do, I would now do domain slash hero digest. where basically I would not, I would always use in web pack configuration now, so I don't have to share the screen. In web pack configuration, you're gonna see, I think it's library. The property where he says library name. So it can always be the same file, remote. I like to use remote.js. To me, that's like index.js to HTML. Sorry, index.html to HTML. Remote.js is that kind of a metafile. But you don't do that domain.com slash remote.js. You would do domain.com slash v1.2.3. v1.2.3. Every time you deploy the app, you increment. You don't increment, but you create folder for that version. So you cannot have two deployments of the same version. That is my point. You guarantee that that version is always going to be available. Yeah, okay. Even to people who use outdated versions of the app. Now, this is not something that is going to be in the documentation of Microfrontends or Module Federation. This comes just from the experience, right? And that worked really well. I know that you may say, oh, so every time I do that, I need to change my URL. So I need to worry about these URLs. But you can help with that too. Some organizations are going to always track version numbers and they're always going to, through their QA process and whatnot, they're gonna nominate the current production version. So they're gonna find a way through some kind of infrastructure where you can say, oh, this is the current version. But you can do something smart. You can create, for example, if you're using Lambda. So if you use Lambda OnEdge function, they're gonna say, if I type one point x, then show me the latest version in the one range. Or if I type slash latest, they show me the latest. Or slash next you show me the latest canary version. I mean, you can play with that.

Rolling Back Versions and Future Opportunities

Short description:

You can roll back a version with a bug when using module federation by building the infrastructure around it. There are multiple ways to approach this. For example, you can create a tool in the backend that retrieves the latest version when using the 'latest' keyword. If a bug is detected, you can programmatically request the last known good version. Alternatively, you can implement your own logic in the frontend to handle version rollback. This can involve tracking and invalidating problematic versions based on reports or using an auto-healing mechanism. Thank you all for the love and amazing feedback. If you're interested in advancing your career, feel free to reach out to Moduscrew.com. We are always hiring and work with various stacks, including module federation. It has been a pleasure being with you today. Thank you for joining JS Nation and this workshop.

You can create parsers like that in the routing. Makes sense, makes sense, thank you. Thank you for your question. Let me see. Let me see, I'm gonna go through this, if you have other questions, interrupt me.

How can I roll back a version with a bug when I'm using module federation? So, it's the infrastructure that you build around module federation. And really there are multiple ways of going through this. So in this example, I said, you can create a tool in the backend that knows when you use keyword latest, it gives you the latest version. So you can say, okay, give me the latest version and give this latest version, and your frontend recognizes a bug and you can even pass exception to see, oh, this is a bug with the feature and then you can say, okay, give me the, you can program the cloud to give you the last known good version, or you can just simply work out your own logic in the frontend to, it's just the how you deploy, it's how you deploy that business logic of your deployment is going to help you understand how you can load the older version, right? The last known good version. Whether you track it, whether you guess with the old version and you invalidate, maybe you invalidate, if you report, you can say, oh, if my, say New Relic reports multiple issues with a version, I'm going to automatically invalidate that version. And in your infrastructure whatever the invalidation means, whether it's deleting the folder, whether it's marking it in RISC-E, whatever you do, you do that and then users load the older versions. In the AutoHealing, you just implement that and say by that additional roundtrip. So your first roundtrip was to your Hero.js and then you know, oh there is an error. But then you have to create another roundtrip, say it didn't work. It didn't work.js right. And then your backend gives you back the older version, right. That's the gist of it. Version subfolder, I think that we just talked about that.

Thank you guys for all the love and amazing feedback. Before we go, let me see. So I work in a company that allowed me to to write something like this on a slide. I was very sarcastic when I wrote this, but not in a negative way. I was just playful. Anyway, if you guys are eventually looking to upgrade your career, feel free to reach out at Moduscrew.com. The company is always hiring, it's growing like crazy. We work with well lots of stacks, but in terms of module federation, I know of at least three big companies that use module federation with Modus. So if you feel like trying it out, feel free to reach out. Yeah, I'm probably going to get fired when someone sees the recording of this message, but I really needed to run with it. Okay, guys, thank you so much. It was such a pleasure to be with you today. Thank you for joining JS Nation. And thank you for joining this workshop.

Watch more workshops on topic

JSNation Live 2021JSNation Live 2021
113 min
Micro Frontends with Module Federation and React
Workshop
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.
JSNation Live 2021JSNation Live 2021
113 min
Micro-Frontends with Module Federation and Angular
Workshop
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.
Prerequisites:You should have some experience with Angular.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
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.
React Advanced Conference 2022React Advanced Conference 2022
22 min
Monolith to Micro-Frontends
Top Content
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.
React Advanced Conference 2023React Advanced Conference 2023
20 min
Micro-Frontends With React & Vite Module Federation
From my experience one of the hardest things is to share information between microfrontends, so in this talk I would like to explain various ways on how to share a design system to ensure uniformity to the application. Another difficult thing is sharing dependencies, fortunately with module federation it can be done, but how can I use different versions of the same library and how does it work behind the scenes?
I'm the creator of module-federation/vite library, with React and this library, I'd like to show you how you can achieve these results by configuring everything correctly.
React Summit 2022React Summit 2022
23 min
Sharing is Caring: (How) Should Micro Frontends Share State?
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.
React Advanced Conference 2021React Advanced Conference 2021
27 min
Micro-Frontends Performance and Centralised Data Caching
Common myths about Micro-Frontends hold that they are bad for performance or that developers implementing this architectural style don’t care about the performance implications because they are focusing on fixing the developer experience and organizational issues rather than focusing on the user experience, however, the reality is altogether different. Micro-Frontends are not inheritably bad for performance and, as is often the case in software development, making best use of the technology depends on correct implementation. This talk will demonstrate how Micro-Frontends can make your applications faster and more resilient while keeping the benefits of independent deployments.