How I implemented Module Federation for Node.js and did something wrong
The problem
Webpack module federation is quite new but has already changed the architectural concepts of building modern web applications. Webpack today is not just a tool for building client-side applications, it can be targeted to multiple environments like Node.js or Electron. But can ModuleFederation be used inside all these supported environments? Can we just include the ModuleFederation plugin inside of a Node.js application and use remote scripts dynamically? Can we have SSR (Server Side Rendering) with ModuleFederation?
For now no.
Really? Let’s try it out. I want to import library ‘remoteLib’ (which is deployed at http://localhost:3002/remoteEntry.js) into my Next.js app and perform it on the server-side.
Part 1. On the Next.js application let’s have a config like this:
And import it on the page:
Now let’s start the Next.js application:
We see an error “document is not defined”. Hmmm, document? I don’t need to use “document” inside my Node.js application. I don’t have it there: webpack, please use document only on client-side!!
Ok, so I think we can do something with that error. As I said before webpack does support multiple platforms. We can build the remote library 2 times: one for web target and one for node. Then on the Next.js side, we can import appropriate remote script depending on the target.
Part 2. On the remote library side, we will have two configs: for web and for node (yeah, webpack config can be an array)
Part 3. On the Next.js side we now should add smth like this:
And again run the Next.js application:
Again same error. But why?
The reason is that for now webpack engine doesn’t support runtime module resolution for other platforms than the web. Even for the “node” build, it tries to import remote scripts via the “script” tag. Sad :(
My solution
My solution consists of two webpack plugins: NodeAsyncHttpRuntime and NodeModuleFederation. The repository is here: https://github.com/telenko/node-mf.
NodeAsyncHttpRuntime is a plugin that replaces the ‘node’ target. It should be used on the remote side to build scripts for Node.js consumers.
NodeModuleFederation is a wrapper around webpack’s ModuleFederation plugin and provides Node.js specific remote dependency resolution rules. It should be used inside the Node.js application (for example Next.js).
Let’s try using it.
Part 4. Let’s use NodeAsyncHttpRuntime on the remote library side:
Part 5. On the Next.js side, we should use NodeModuleFederation (for the server-side only)
Let’s run the Next.js application now:
Wow, it’s working, but… Do we have SSR for sure?? Let’s use Postman to be sure that page HTML contains our changes:
We do have SSR now :)
The full example of using my plugins can be found here https://github.com/telenko/node-mf-example
How is it working?
Unlike to web browser engine, Node.js doesn’t have support for remote script execution (no possibility to just add <script src=…> tag). The only possible way is to fetch a script via HTTP request and eval it inside a Node.js application. That’s what exactly I’m doing in my plugins.
You may ask about performance. Yeah, I’m not an expert in Node.js but anyway eval is not the best thing to achieve good performance. V8 just won’t have a possibility to optimize a script.
Security?
This is another risk. Again, sorry full-stack engineers and backend developers — I have no so much backend experience, but for sure running remote scripts on the backend side is a bad idea. On the client-side we can use scripts from any locations, but the browser itself is the main player who observes the security of that (CORS for example). On the backend side developers themselves should care about security and should be 100% sure of the code which is running and HTTP resources they are using.
Although in the case of Next.js applications, Node.js is used to build view layer only, we should not perform queries to the database or so. So maybe in the case of the Next.js it is ok, but for more secured layers of backend application (REST) it is not recommended to use.
So let this be a topic to discuss for the community. I’m not sure for now.
Conclusion
I hope I made the web community closer to the vision if Module Federation is suitable everywhere or only on the client-side.
Thanks for reading!