Micro-frontend using Module federation

Micro-frontend

Micro frontends is an architectural used to break down a big website into smaller frontends. Imagine you work for a big-ass company and you have one team responsible for the navbar, one team responsible for the footer etc.

Warning

This is why you stay away from big companies!

It can also be useful if you have several static websites which you would like to run next to each other, sharing things such as login but one website is using react-12 and the other website is running the newest a shiniest version of react.

Let’s see how we can do this using vite and deploy everything in a docker container(This kind of defeats the purpose of being able to deploy different components independently ¯\(ツ)/¯ )

Host

Let’s start with the host-app, this will be the main app pulling in the other remote app(s).

npm create vite@latest

Replace the vite.config.ts with the following:

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react-swc';
import federation from '@originjs/vite-plugin-federation';

interface Imodules {
  remote: string;
}

export default ({ mode }) => {
  process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
  const modules: Imodules = {
    remote: '/remote/assets/remoteEntry.js',
  };
  if (mode === 'development') {
    modules.remote = `http://localhost:3002${modules.remote}`;
  }
  return defineConfig({
    plugins: [
      react(),
      federation({
        name: 'host-app',
        remotes: {
          remote: modules.remote,
        },
        shared: ['react'],
      }),
    ],
    build: {
      target: 'esnext',
    },
  });
};

The modules.remote will tell the host-app where to find the remote app.

In your app.tsx add the following line to import the remote-app:

const RemoteApp = lazy(() => import('remote/Remote'));

Remote

In your remote app, update your vite.config.ts to look something like this:

import { defineConfig, loadEnv } from 'vite';

import federation from '@originjs/vite-plugin-federation';
import react from '@vitejs/plugin-react-swc';

export default ({ mode }) => {
  process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
  const base = process.env.DEV ? '' : '/remote';
  return defineConfig({
    plugins: [
      react(),
      federation({
        name: 'remote-app',
        filename: 'remoteEntry.js',
        // Modules to expose
        exposes: {
          './Remote': './src/app.tsx',
        },
        shared: ['react'],
      }),
    ],
    base: base,
    build: {
      target: 'esnext',
    },
  });
};

Here we specify what to expose (app.tsx)

Run everything together

To run everything together I like to use docker, here is an example Dockerfile I used.

In the Dockerfile I use nginx as a reverse-proxy to serve the static content, my nginx.conf file:

server {
  listen 3000;

  location / {
    root /usr/share/nginx/html/host;
    include /etc/nginx/mime.types;
    try_files $uri $uri/ /index.html;
  }

  location /remote/assets/ {
    alias /usr/share/nginx/html/remote/assets/;
    include /etc/nginx/mime.types;
    try_files $uri $uri/ /index.html;
  }
}

The / path is pointing to my host app and /remote/assets/ is pointing to my remote app. When you hit / the host app will tell your browser to fetch data over at /remote/assets/.

And just like that we have created a trendy micro frontend.

Code

All the code can be found here

comments powered by Disqus

Related Posts

Accept interface return struct

Accept interface return struct The term Accept interface return struct was first coined by Jack Lindamood in this article .

Read More
Why blogging

Why blogging

Welcome to my blog! In this inaugural post, I want to share my motivations and aspirations behind this venture.

Read More

Graceful shutdown of server in Go

Graceful shutdown Graceful shutdown refers to shutting down an application or service in a way that allows it to finish any ongoing tasks or transactions, clean up resources, and exit in an orderly and controlled manner.

Read More