Microfrontends, Architecture and Trade-offs

Share this post

Server side Rendering with Module-Federation

microfrontends.substack.com

Server side Rendering with Module-Federation

Overview and Trade-off Analysis

luis vieira
Jan 31
Share this post

Server side Rendering with Module-Federation

microfrontends.substack.com

In the last issue, we looked into the fundamentals of how to use module federation in microfrontend architectures. However, the implementations analized had a particularity: they only worked on the client side.

It is a very common requirement, for web applications these days to do some form of server-side rendering (SSR) and although SSR works with module federation, it comes with some particularities.

Module federation allows you to split your application into separate builds and deploy them independently. In the browser, they will act as a monolith, attempting to share dependencies and importing code from each other while running inevitably together in the same browser window.

When doing SSR, the same working model is transferred to the server and federation is straightforward to configure. When comparing the client to the server configuration, they are quite similar.

module.exports = {
    client: new ModuleFederationPlugin({
        name: "shell",
        filename: "shell.js",
        remotes: {
            remote1: "http://localhost:3001/client/remoteEntry.js",            
        },
        shared: { 
            'react': { singleton: true }, 
            'react-dom': { singleton: true },
        }
    }),
    server: new NodeFederationPlugin({
        name: "shell",
        filename: "remoteEntry.js",
        remotes: {
            remote1: "http://localhost:3001/server/remoteEntry.js"
        },
        shared: { 
            'react': { singleton: true }, 
            'react-dom': { singleton: true },
        }
    }), 
}

But not only the same model is used for configuration, also the same runtime behaviour is adopted. This means that, although you have independent builds and deployments, your Host application will act as a monolith on the server.
There will be one server, responsible for rendering all the remotes it is connected to.

The high-level view looks like this:

A Host application on the server will fetch code from the remotes it is connected to, which essentially act as static asset servers, then this code will be executed in the Host application using Node VM.

This model doesn’t come without controversy to say the least. However Importing remote code into a server side application is something that may be in the horizon for node applications, Deno already supports this.

import {
  add,
  multiply,
} from "<https://x.nest.land/ramda@0.27.0/source/index.js>";

In the example you may notice that a specific version is requested. But what happens if the content in the remote URL changes?

Deno provides specific tooling for downloading and integrity checking the resources you depend on and can be instructed to store subresource integrity for modules in a local file using this as a validation mechanism protecting against runtime code changes.

{
  "<https://deno.land/std@0.164.0/textproto/mod.ts>": "3118d7a42c03c242c5a49c2ad91c8396110e14acca1324e7aaefd31a999b71a4",
  "<https://deno.land/std@0.164.0/io/util.ts>": "ae133d310a0fdcf298cea7bc09a599c49acb616d34e148e263bcb02976f80dee",
  "<https://deno.land/std@0.164.0/async/delay.ts>": "35957d585a6e3dd87706858fb1d6b551cb278271b03f52c5a2cb70e65e00c26a",
   ...
}

But this is not about Deno, this is just an example about some tooling you may need to build if you want to support module federation on the server, all of this doesn’t come by default and may need careful consideration.
You may also want to consider some kind of service discovery implementation for remotes.

Check Deno docs for more info about how integrity checking works https://deno.land/manual@v1.28.0/basics/modules/integrity_checking

There are also some other issues to consider. For example, in terms of scalability, it can be hard to predict how changes to a remote would affect the Host resources consumption, unless they are tested together. When this need to test things together arises, it’s always a red flag, and we come back to the issue of coupling.

Also if a Host starts having issues due to a remote, who is responsible for fixing the issue?

As a final remark, I would like to emphasize that module federation may appear to be an easy solution to implement both on the server and client, however, there are some unique aspects and potential risks that must be considered before jumping into it.

Thanks for reading Microfrontends, Architecture and Trade-offs! Subscribe for free to receive new posts and support my work.

Share this post

Server side Rendering with Module-Federation

microfrontends.substack.com
Comments
TopNew

No posts

Ready for more?

© 2023 luis vieira
Privacy ∙ Terms ∙ Collection notice
Start WritingGet the app
Substack is the home for great writing