Check out a free preview of the full Vite course:
The "Module Federation" Lesson is part of the full, Vite course featured in this preview video. Here's what you'd learn in this lesson:

Steve delves into the implementation of Module Federation using Vite. The process of building a library, hosting it on the internet, and allowing consuming apps to fetch and use the module at runtime is covered in this segment.

Get Unlimited Access Now

Transcript from the "Module Federation" Lesson

[00:00:00]
>> So let's talk about how to do module federation using Vite. Module federation is, a term of art which I'm pretty sure was made up by the Webpack team but it's cool. But it is mostly the popular in a lot of the micro-frontend architecture, which I'm just gonna go on record saying, I don't think it's the best idea in the world.

[00:00:25] But there are use cases, even if you whether or not you agree with me on that one, where it is kind of useful. So the idea is if you have a bunch of smaller apps that all need the same component, and the library would theoretically work except, let's say you update the navbar, right?

[00:00:43] Well, now you've got to push that new navbar to every repo, which I would say, I just don't have that many repos. But it's not always that easy. And, for instance, this is something that I need to do because we have a team portal, we have a marketing site, right?

[00:00:58] We just got a navbar, just one thing about navbar. And then you have the question of wouldn't it be nice that we had the same navbar on the dark side and the education side of money? Yeah, that would be nice. And what I don't wanna do, is every time I build a navbar, what I don't wanna do is then have to then bump the package version of my library in four different repos, right?

[00:01:21] Will I do it if I need to, sure. Do I want to, no. So what module federation does is basically allows you to build a library and then put it somewhere on the Internet, VSL S3 bucket, what have you, wherever you want somewhere where it's hosted by a server.

[00:01:38] And then the consuming apps can load and fetch that module at runtime and put it in place, right? So it's kind of an extension on what we have with the library, but then we also want the ability to kind of serve it, right? And then you need those other ones to know how to kind of get that remote module, fetch it, and install it in the page.

[00:02:02] And like I said, that is in a lot of ways very powerful, right? Because it saves you a lot of work because now you can just literally update the module and then everyone who needs it has the new version immediately. It terrifies me I'm willing to do it for the marketing side.

[00:02:20] It terrifies me for the code app because a change by one team could theoretically affect something on the product that I can get paged over, and I don't like getting woken up in the middle of the night. So we will do it on stuff where I have a fallback, and fall back to the old navbar, otherwise, but taking down production cuz a deploy is a different thing.

[00:02:45] But I think there are architectures built on it. And there are a lot of really practical use cases as well. And I think when you need it and when used with a little bit of discretion, is a powerful pattern. So there is a plugin that we can use, this origin, it's a namespaced plugin.

[00:03:05] But originjs/vite-plugin-federation, you can use this on both the hosting side as well as the receiving side. So we'll go ahead and we'll give it a shot in our component app that we were using earlier, that's the consuming app. Cool, and let's make sure I've got all that committed.

[00:03:37] Yes, I do. We're gonna do git checkout -b live-coding-module-federation. Cool, and we've got all that in place. So let's do that npm install now. We've got the npm install originjs module federation save-dev. We've got that in place. And so now, we're gonna swap out some of our configuration before, cuz now we're gonna build this library a little bit differently.

[00:04:11] So in this case, we don't need all of the same plugins. Theoretically, I don't even think I need the react one per se. So let's take it out for a second. We'll take out almost all this stuff, cuz now we're effectively gonna serve this module in a different version, right?

[00:04:34] Too many braces, cool. So now we can pull out all of this. And what we're going to say is, Well, actually, we need to keep the react one, I'm sorry. Got a little carried away there. All right, so we've got the react, put that back in there, cuz like, awesome.

[00:05:00] And then what we're gonna do is we're gonna pull in, import federation from that origin, yeah, that's what we want. It's nice when it completely works on your behalf. And so the component is gonna be our host, no this is gonna be the remote app. And so what we'll say is, We'll say the name here, yeah, remote app, whatever you wanna say.

[00:05:36] All right, and so we've got the federation, which kind of sounds very star tricky. So I'm kinda into it. We do need to say, federation, there we go. And here now we should have some order completely on our hands, we'll say name, fem-components. Right, we've got that. All right, so the file name.

[00:06:03] The file name is basically when we go and ask for a component, there's gotta be a file that's kind of generated that's gonna say, here's the component that you asked for. And so, the convention most of the time is this remoteEntry. So as long as it's the same, it doesn't actually matter, but we'll have that in place.

[00:06:25] And then you'd have to say, basically, what it exposes, right? And so, what are the modules that are available? And this is pretty straightforward, so this is something like, button is the src/components/button.tsx. And then we can do the input too, which is ./src/components/input.tsx. Awesome, and then very similar to what we had with the externals before, we'll say shared and we'll go through and we'll say, okay, like react, they should start consuming this plugin they should already have react and react-dom, sweet, and yeah.

[00:07:19] Let's try that out. And let's make sure that we've got the correct format for the module. So I'm gonna say, esnext. Remember if I need that corrected, but panicky enough that I wanna make sure that I've got the correct format of the modules. And that should do the trick in terms of serving, right?

[00:07:48] Then we also need to then receive, right? And so we had that other library before. Let's see, let's go in here. We got this vite-react. Let's pull this one up. And then the consuming code is very similar as well. So we can kinda pull that together too. And so here we're gonna say, Vite-react.

[00:08:17] We will get rid of these for a second cuz we're not pulling in the library anymore. We do need to install the same library that we had earlier. So this npm install @originjs, right? And cool, so we've got that in place, and so we'll go into the vite.config here as well, and we'll do a little bit.

[00:08:38] It's very similar except we're now on the receiving end. I gotta import that up here as we did before. @originjs, except this point we are now on the host side. So we'll say, name, Host-app, then the remotes. And so this is where and like TypeScript is gonna get a little angry with us.

[00:09:11] You could figure out clever ways of getting the type files. Generally speaking, what I do is I, well, actually receive apps on my end are JavaScript. The one with the components on my end is the TypeScript one. At this point I would also have a library with the types in it cuz that's better than trying to get.

[00:09:28] TypeScript gets very angry in your editor if you don't have like, the VS code doesn't know that they're remotely somewhere else. So having the types locally makes sense, but we're not gonna worry about that. We'll probably do it mostly in JavaScript. And then you kinda give it effectively like, we're gonna treat it almost like it's a module, right?

[00:09:46] So you give it some, we'll call it the other one, femd as before. We call it vite-react components, we'll call it femds. And that is going to be the location of the remote server, right? For me right now, this is all local. What I'm gonna end up doing is, I'll use the preview server, just as a local host so we can get to it.

[00:10:10] So we'll say localhost:4173, and then /assets/remoteEntry. That's the same file we set on the other side. So as long as they match, we should be good to go. And then we just say, again, the shared is react and, no, Someone remind me, I gotta put a comment in there since I'm done typing.

[00:10:42] All right, so let's go in this one here and we're gonna just host it real quick. So we'll do an npm run build. Cool, and you can say it did a whole bunch of stuff. The plugin is doing most of the work here, is put together the things we need.

[00:11:01] If some of these dependencies are on the other side, we might not choose to have this as a library that helps concatenate class names, right? You can choose the level of which you wanna have some other libraries included or not. That all depends on your particular situation, but you can see that we've got very similar to what we've seen previously.

[00:11:23] If I wanted to take out the vite.svg, I could do copy public directory as well. Right now, this could be an app that I also choose to host, that is its own thing and is also serving these modules. So I'm gonna keep it cuz I think that's totally fine in my case.

[00:11:38] Now the big difference here is that we don't have these at build time, right? We are fetching them after the fact. Now, depending on your framework of choice, this is gonna be a little bit different. It's gonna be a little bit different in Vue than Svelte, than React.

[00:11:53] With React, if we're doing loading of components that are asynchronous, we've got to use suspense and react.lazy to go get it. Totally fine, if you're using Vue, if you're using Svelte, the semantic's are gonna be different. The important part is how to set up both what is kind of the remote, where the components are, and then on the receiving end, how to pull those components in.

[00:12:15] So what we'll do is we'll go back over to the receiving end, and in here we're basically gonna say, const Button = react.lazy, and we'll say, And react.lazy basically takes one of these import statements that we've seen before. So we'll have import, and what do I call it?

[00:12:48] Fem, and I'm not writing this in the right file. So good, cuz I needed to go back to this file. I called it just femds. Cool, so we'll do femds/button. And like I said, I can do, Stuff in terms of the types. Again, I would probably have a DTS file here and just pull it in along those lines, depending if you need it.

[00:13:27] We're not gonna worry too much about the types right now, but what we are gonna do is we're gonna get that button. We do need to put this inside of react.suspense. So this react suspense is, again, this is react specific, if you're not using react, you don't need it.

[00:13:45] But it's basically saying some asynchronous stuff is happening in here. So we'll go ahead and we'll say, Yeah, let's put that in place, and we do need to make sure that the server is running. This is the stuff that scares me of all this stuff. Now, S3 VSL, it's a little bit I'm being a little hyperbolic, because at the end of the day when we did all that code splitting, we were fetching stuff remotely even in our own app.

[00:14:14] It's just mostly like if you have a third-party dependency, you have another thing that could break.