[00:00.000 --> 00:10.440] My name is Bipal and today I'll be talking about micro front ends. [00:10.440 --> 00:14.920] The title might be a bit misleading because it says in React, whereas it's general and [00:14.920 --> 00:18.280] can be applied to other libraries or frameworks. [00:18.280 --> 00:24.120] The main focus of my talk is around Webpack's plug-in called module federation, which allows [00:24.120 --> 00:31.040] this paradigm of micro front ends to be possible. [00:31.040 --> 00:33.200] So yeah, what are micro front ends? [00:33.200 --> 00:35.280] Front ends for ants or something like that? [00:35.280 --> 00:36.280] No. [00:36.280 --> 00:39.920] So, oh yeah, before I dive into micro front ends, something about me. [00:39.920 --> 00:42.840] I work as a UI developer for IBM. [00:42.840 --> 00:45.680] Work on the OpenShift Data Foundation product. [00:45.680 --> 00:53.280] So we use this extensively in our product and that's how I got to learn about this feature [00:53.280 --> 00:57.120] and it's not something that is written or created by me. [00:57.120 --> 01:02.040] It's more of an open source project created by some guy named Scripted Alchemy. [01:02.040 --> 01:08.040] I don't know his real name, but that is his GitHub user ID. [01:08.040 --> 01:13.320] So if you missed the description of my talk in the Foshtem website, I'll be basically [01:13.320 --> 01:20.240] talking about creating, going away from monoliths to this micro front end paradigm where basically [01:20.600 --> 01:24.640] traditionally what we would do is we would have this huge repository and we would have [01:24.640 --> 01:30.040] all the code for, let's say if it's a 10 page web application, then you'd have all the code [01:30.040 --> 01:33.160] for all the 10 pages in the same repository. [01:33.160 --> 01:37.320] But to make things easier to decouple all these teams which are working on these various [01:37.320 --> 01:43.520] different pages, there is this paradigm where you can divide these various pages into different [01:43.520 --> 01:44.840] repositories. [01:44.840 --> 01:49.680] So you would create different builds of these different pages and integrate them in runtime. [01:49.680 --> 01:54.680] So you're not being stopped or you're stuck to the same release cycle as for the other [01:54.680 --> 01:59.440] teams who are working on the various other pages. [01:59.440 --> 02:05.160] So to explain it with a simpler analogy, I would use something like building a house [02:05.160 --> 02:06.760] or building a hotel. [02:06.760 --> 02:11.000] So there is one team which would build, I guess, the core of the house and then there's [02:11.000 --> 02:14.240] a team which would install the electrical wiring and there's other team which would [02:14.240 --> 02:16.840] do the interior decoration. [02:16.840 --> 02:22.040] So in the end, all these efforts are combined and you get a hotel in the end. [02:22.040 --> 02:26.920] Similarly, you have a team which creates, say, the home page, the other team creates [02:26.920 --> 02:32.880] the calendar component, some other creates other component libraries that are used in [02:32.880 --> 02:38.520] your project and you can all seamlessly integrate them in the runtime. [02:38.520 --> 02:44.600] So that would help you avoid reusing the code and basically all the benefits that you would [02:44.600 --> 02:51.160] get by following the dry principles and the solid principles. [02:51.160 --> 02:56.520] So more about module federation, it came in Webpack 5. [02:56.520 --> 03:00.440] It came as part of Webpack 5 and yeah. [03:00.440 --> 03:07.840] So the main concept around it is of having different modules, the remote modules and [03:07.840 --> 03:09.360] the local modules. [03:09.360 --> 03:13.760] So let's say you have your host application, Application 8, which ships with the home page. [03:13.760 --> 03:17.640] Now it has its local modules related to the React. [03:17.640 --> 03:20.000] Let's take React as an example. [03:20.000 --> 03:24.160] It would have your React components related to the home page. [03:24.160 --> 03:29.040] Now say you click on the About Us page, then what it would do is it would fetch modules [03:29.040 --> 03:34.640] from a remote location, a different web server where you are deploying the bundles related [03:34.640 --> 03:36.200] to About Us page. [03:36.200 --> 03:39.880] And those are known as remote modules and you would basically pull it into the runtime, [03:39.880 --> 03:45.280] create it over there, which would be handled by Webpack, obviously, and you would get your [03:45.280 --> 03:49.400] module federation. [03:49.400 --> 03:58.360] So the problem that this helps solve is that monoliths are growing bigger and bigger. [03:58.360 --> 04:06.040] Once it goes bigger, the build time increases, there is a lot of dependence across the multiple [04:06.040 --> 04:08.560] teams that are working on the same repository. [04:08.560 --> 04:10.480] In the end, it makes things harder. [04:10.480 --> 04:15.320] If we go back to the olden times before microservices was there, you would have a bunch of teams [04:15.320 --> 04:19.000] working together and everything being deployed at the same place. [04:19.000 --> 04:20.520] That caused its own issues. [04:20.520 --> 04:25.040] Now since the front ends are getting larger, it is bringing its own set of problems. [04:25.040 --> 04:31.080] So basically this is what module federation aims to solve that issue. [04:31.080 --> 04:37.080] So like I explained previously as well, let's say you have application home page in About [04:37.080 --> 04:43.280] Us, then using this method, you could split the repositories, split the projects, build [04:43.280 --> 04:48.720] them separately, and combine them at the runtime. [04:48.720 --> 04:53.360] So let's take an example of how a single build application would work. [04:53.360 --> 05:01.840] So first you send a get request from the browser and then it would return the index file. [05:01.840 --> 05:06.280] From there, the script tag would ask to load for the main bundle. [05:06.280 --> 05:10.240] And then if there are other buttons or anything that you use over there, those would also [05:10.240 --> 05:11.640] get pulled from there. [05:11.640 --> 05:15.080] I have missed some of the responses from the server. [05:15.080 --> 05:17.480] Sorry about that. [05:17.480 --> 05:21.440] But with multiple application, it would be something different. [05:21.440 --> 05:26.000] So you would have your web server A, which would be the host application server, where [05:26.000 --> 05:30.400] you would have your index file, the main bundle, and some of the chunks that are coming from [05:30.400 --> 05:32.440] the main bundle. [05:32.440 --> 05:38.400] And you would have your second web server where you host your remote bundles. [05:38.400 --> 05:44.160] So this is a setup where you have one host and one remote application. [05:44.160 --> 05:48.960] So the first, it would ping the host application. [05:48.960 --> 05:56.160] It would get the index file, pull the module that is related to, that is sort from there. [05:56.160 --> 06:03.520] And then it sees that it requires something like a button bundle, a button component in [06:03.520 --> 06:04.760] the home chunk. [06:04.760 --> 06:08.120] Then it would basically ping to web server B and get that. [06:08.120 --> 06:16.960] So how it figures out that it needs to ping web server B and where actually the button [06:16.960 --> 06:21.440] bundle is, is something that I'll go after this slide during the code demo. [06:21.440 --> 06:30.200] So pretty much if you look into the requests that go as, similarly, it hits your main application [06:30.200 --> 06:33.320] server, then it gets the main bundle. [06:33.320 --> 06:35.040] And then if you see here, there's something different. [06:35.040 --> 06:43.000] It hits local host 3000 instead of 3001, and it looks for this file called remote entry.js. [06:43.000 --> 06:51.320] So let me go to the code and explain it a bit better than what I did so far. [06:51.320 --> 06:54.000] All right. [06:54.000 --> 06:55.960] This is my remote application. [06:55.960 --> 07:00.920] Let me go to my host application. [07:00.920 --> 07:07.120] Is this visible? [07:07.120 --> 07:08.360] Awesome. [07:08.360 --> 07:14.680] So the most important part of this configuration is the plug-in part, which is module federation [07:14.680 --> 07:15.960] plug-in. [07:15.960 --> 07:22.400] So here what we're doing is we're specifying the remotes. [07:22.400 --> 07:27.480] So in the remotes, you can see that I specify remote module, and I specify that it is at [07:27.480 --> 07:29.960] local host 30002 slash remote entry. [07:29.960 --> 07:32.360] So this remote entry is a special JavaScript file. [07:32.360 --> 07:36.880] It does not have any code-related chunks over here. [07:36.880 --> 07:41.520] I mean, none of the application-specific code is present here. [07:41.520 --> 07:47.480] It's just a way for Webpack to expose the modules that you're trying to expose from [07:47.480 --> 07:50.440] your remote build. [07:50.440 --> 07:55.040] So you see that I specify remote module as presented that. [07:55.040 --> 08:00.800] So Webpack knows where to hit to connect to the remote build. [08:00.800 --> 08:08.240] And something related to React and similar libraries is that I have mentioned that React [08:08.240 --> 08:10.160] and React DOM are shared. [08:10.160 --> 08:16.160] So that means there are not multiple instances of this library being loaded into the runtime. [08:16.160 --> 08:18.920] And I also make sure that it is singleton. [08:18.920 --> 08:24.600] That means only one instance of it is present there, because if you have multiple instances [08:24.600 --> 08:28.320] of libraries like these, it would not work well together. [08:28.320 --> 08:32.320] So hence, you have to mention that it's singleton. [08:32.320 --> 08:40.520] And similarly, if we go to the remote bundle, you see that here what I do is I specify the [08:40.520 --> 08:47.160] file name for the remote entry, and then I expose this component-named button. [08:47.160 --> 08:52.800] If you see here under source, there is this component-named button, which I have exposed [08:52.800 --> 08:54.560] through there. [08:54.560 --> 09:00.040] And in my host application, I go here and I import button. [09:00.040 --> 09:04.880] And you can see here I import it from remote module slash button. [09:04.880 --> 09:10.680] And Webpack knows basically this is not part of your node modules. [09:10.680 --> 09:16.520] And it has to pull it from a remote source, which it does. [09:16.520 --> 09:26.320] So let me try and run this, if we see here. [09:26.320 --> 09:28.080] And we get a warning, perfect. [09:28.080 --> 09:29.680] But we can always ignore the warning. [09:29.680 --> 09:34.520] And you can see that there's a toggle button that comes up. [09:34.520 --> 09:41.080] And I would just like to show a few things on the network tab as well. [09:41.080 --> 09:44.040] Let's see that warning one more time, all right. [09:44.040 --> 09:47.200] So the first thing that it loads is the main bundle. [09:47.200 --> 09:52.400] Then you can see that there is the remote entry that comes from the 3002. [09:52.400 --> 09:57.040] And then only after that, the button is actually getting pulled over here. [09:57.040 --> 10:01.760] So it gets the remote entry, it sees what chunks are present over there, and basically [10:01.760 --> 10:05.560] pulls the button chunk from there. [10:05.560 --> 10:07.400] And you can see that the button is working. [10:07.400 --> 10:13.800] So it's a remote module that's coming over here. [10:13.800 --> 10:20.440] Some of the links that are useful are the documentation for module federation, which [10:20.440 --> 10:23.080] is hosted on the Webpack site. [10:23.080 --> 10:29.200] And something that I would like to also mention is the OpenShift Console project, which uses [10:29.200 --> 10:30.200] this. [10:30.200 --> 10:33.200] I think we were one of the first people to use it. [10:33.200 --> 10:42.240] So OpenShift Console is a project user interface for enterprise distribution of Kubernetes, [10:42.240 --> 10:46.240] which is also known as OpenShift created by Red Hat. [10:46.240 --> 10:53.720] One interesting use case that we had is we had one static application with a bunch of [10:53.720 --> 10:58.080] plugins that were all pushed into the single repository. [10:58.080 --> 11:02.360] So we had like eight products along with the core application that were shipped together, [11:02.360 --> 11:05.160] and all our release timelines were synced because of that. [11:05.160 --> 11:09.720] And that would cause massive headaches for PMs of multiple products because it would [11:09.720 --> 11:12.440] stop the release for other product and so on. [11:12.440 --> 11:18.280] So what we did was we basically removed all the plugins from the same repository and created [11:18.280 --> 11:28.320] a different repository for them and combined all of them in the runtime using this same [11:28.320 --> 11:30.120] plugin of Webpack. [11:30.120 --> 11:37.800] So this has helped us tremendously to have our own release cadence and send bug fixes [11:37.800 --> 11:44.160] at whatever time we want to and not be stuck with one timeline for all the products. [11:44.160 --> 11:48.360] So in the end, yes, it has helped a lot to us. [11:48.360 --> 11:50.880] So with that, that's all from my side. [11:50.880 --> 11:51.880] Any questions? [11:51.880 --> 12:18.720] To what degree does this send box code and or impact security? [12:18.720 --> 12:24.560] It does impact security because it gets access to the whole of runtime. [12:24.560 --> 12:29.000] That's why you would do this something with applications that you would trust. [12:29.000 --> 12:36.400] And if it is something of a third party, it's usually safer to sandbox things. [12:36.400 --> 12:42.160] I wondered what happens if the server with the remote components is down but not the [12:42.160 --> 12:48.480] whole environment, I think that could lead to very weird user experience bugs. [12:48.480 --> 12:51.800] Yes, that would lead to a very bad user experience. [12:51.800 --> 12:58.040] So you'd make sure that the remote application is also working but there is some other things [12:58.040 --> 12:59.040] that you could do. [12:59.040 --> 13:03.720] There are fallbacks that you can mention there for dependencies which would not crash the [13:03.720 --> 13:06.200] whole application. [13:06.200 --> 13:10.680] You mentioned that for now it's on Webpack. [13:10.680 --> 13:14.640] Would other bundlers have something similar? [13:14.640 --> 13:17.720] I am not sure about that. [13:17.720 --> 13:24.720] Thank you. [13:24.720 --> 13:30.120] Yeah, probably similar to the security question but how does this, if you've got a system [13:30.120 --> 13:37.240] where users have to authenticate and now you've got a web token that potentially the different [13:37.240 --> 13:44.600] micro front ends need to have access to, yeah, how's that kind of handled? [13:44.600 --> 13:48.720] I think we faced something similar when we were deploying our application. [13:48.720 --> 13:52.400] So basically what we did was we had our own proxy in the back end. [13:52.400 --> 14:00.120] So instead of doing the direct course request like I did, like it hit to 3002, we would [14:00.120 --> 14:06.360] put a proxy between the web application and the different backend servers that we had. [14:06.360 --> 14:12.840] And the proxy would basically add all the credentials that you would require. [14:12.840 --> 14:17.360] I was just wondering how it impacts the performance on the server because you have several instance [14:17.360 --> 14:19.120] of the code running at once. [14:19.120 --> 14:21.040] Sorry, I didn't get you. [14:21.040 --> 14:27.320] I was wondering how much it impacts the performance to split the code like that. [14:27.320 --> 14:32.360] Once the bundles are loaded into the runtime, it does not make a difference because it's [14:32.360 --> 14:35.520] as if it's the same build once it enters. [14:35.520 --> 14:40.880] So the only difference is that, yes, the chunk loading operation might add a few network [14:40.880 --> 14:47.280] calls and it's limited to that performance penalty. [14:47.280 --> 14:59.640] Yes, thank you. [14:59.640 --> 15:00.640] Thank you for the talk. [15:00.640 --> 15:01.640] It was very interesting. [15:01.760 --> 15:05.600] Yeah, I was just wondering, well, it's kind of like something that I kind of want to verify, [15:05.600 --> 15:06.600] I guess. [15:06.600 --> 15:10.760] This would be maybe also something that you could very well use for scenarios where you [15:10.760 --> 15:16.960] would normally like lazy loads stuff, but then instead take you from another location, [15:16.960 --> 15:18.120] right? [15:18.120 --> 15:22.200] Because like, I mean, otherwise it would affect the first paint, I would expect. [15:22.200 --> 15:24.960] Oh, could you repeat your question, sorry. [15:24.960 --> 15:31.720] So like, this would be more for scenarios where you would, like if you load normally [15:31.720 --> 15:36.720] when you route to pages, for example, you know, you would lazy load things. [15:36.720 --> 15:40.880] But in this case, it seems like if you load from a remote location, it's not instantaneous. [15:40.880 --> 15:43.160] It doesn't load instantaneous. [15:43.160 --> 15:48.840] So it would be better in those scenarios and it would be like for if you would load a page [15:48.840 --> 15:54.200] and you want to show a lot of stuff on first paint because it seems a bit delayed. [15:54.440 --> 16:01.560] Yes, that is there because since when you call it from another location, there is added [16:01.560 --> 16:03.120] step of loading that chunk. [16:03.120 --> 16:07.480] So yes, if you have too many components on the initial page, you'd rather have it in [16:07.480 --> 16:17.400] the original host application and not load it from remote. [16:17.400 --> 16:23.560] What's the difference between this technique and Angular's way of doing lazy loading? [16:24.040 --> 16:30.040] Lazy loading is basically you delaying the operation, delaying the loading of the chunk [16:30.040 --> 16:31.720] until it is required. [16:31.720 --> 16:35.680] Whereas here you are loading it from an entirely different place. [16:35.680 --> 16:38.240] Angular would not allow that with lazy loading. [16:38.240 --> 16:41.560] If you try to do it from a different place, it would just fail. [16:41.560 --> 16:47.240] But this is, this allows you to get it from other places as well. [16:47.240 --> 16:51.560] Yeah, I just want to correct that it exists for Angular, a specific way to lazy load from [16:51.560 --> 16:54.120] a different server from another friend. [16:54.120 --> 16:59.880] But just my question was, you say that you were extracting some code from your repository [16:59.880 --> 17:04.320] and you said also that you wanted to share some libraries like React. [17:04.320 --> 17:06.360] How do you manage multiple versions of React? [17:06.360 --> 17:10.840] If each team wants to upgrade to its own version of React, then you duplicate the React library [17:10.840 --> 17:12.120] many times, right? [17:12.120 --> 17:13.120] Yes. [17:13.120 --> 17:18.040] So here, let me just show you, maybe I've not mentioned it here. [17:18.040 --> 17:22.640] But you could have a thing called expected version over here. [17:22.640 --> 17:26.840] And with that, you could tie it to a certain version only. [17:26.840 --> 17:31.480] With that, you would manage the different versions of React issue. [17:31.480 --> 17:35.240] Is there a question? [17:35.240 --> 17:36.240] Any questions? [17:36.240 --> 17:37.240] Sure. [17:37.240 --> 17:38.240] Thank you. [17:38.240 --> 17:54.440] The MIM project has to know before the definition of the remote component, or is this completely [17:54.440 --> 17:55.440] independent? [17:55.440 --> 18:00.560] It could be known in runtime. [18:00.560 --> 18:05.160] For the better developer experience, what usually we do in a production environment [18:05.160 --> 18:10.480] is that we export the types of the components that are part of the remote module so that [18:10.480 --> 18:14.000] it helps the developer know that before time. [18:14.000 --> 18:17.920] But the components do come in runtime only. [18:17.920 --> 18:25.200] But in compilation time of the parent of the main project, he has to know the definition [18:25.200 --> 18:28.160] of the remote, right? [18:28.160 --> 18:30.640] If you're using TypeScript, then it would require types. [18:30.640 --> 18:32.880] But for JavaScript, it would just be a promise, right? [18:32.880 --> 18:34.880] And then it would resolve later on. [18:35.600 --> 18:36.600] Okay. [18:36.600 --> 18:46.440] About the dependencies, it's only about React. [18:46.440 --> 18:51.400] You can use it there, the expected, or rather, for example, I don't know, material UI. [18:51.400 --> 18:58.040] Yes, you could share any kind of dependencies between different bundles. [18:58.040 --> 19:04.040] And then remote module, you could use a module like from NPM if you publish it and you can [19:04.040 --> 19:06.560] use it there. [19:06.560 --> 19:14.960] So remote module usually should point to another build of a webpack, sorry, should point to [19:14.960 --> 19:19.920] another build of a webpack application that uses this particular plugin. [19:19.920 --> 19:24.600] Well, is that it? [19:24.600 --> 19:25.600] All right. [19:25.600 --> 19:26.600] Thank you so much. [19:26.600 --> 19:27.600] Thank you.