Skip to content

Commit

Permalink
add blog post for micro frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Sjoberg committed Feb 28, 2024
1 parent e3ce24a commit 6728219
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 39 deletions.
143 changes: 143 additions & 0 deletions content/english/blog/frontend/module-federation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
title: "Micro-frontend using Module federation"
meta_title: ""
description: "Micro-frontend using module federation with vite and docker"
date: 2024-02-27T05:00:00Z
categories: ["frontend", "react", "vite"]
author: "Hugo Sjoberg"
tags: ["frontend", "react", "vite"]
draft: false
---

# 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.

{{< notice "warning" >}}
This is why you stay away from big companies!
{{< /notice >}}

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).

```bash
npm create vite@latest
```

Replace the `vite.config.ts` with the following:

```ts
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:

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

# Remote

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

```ts
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](https://github.com/hugosjoberg/blog-code/blob/main/vite-module-federation/Dockerfile) I used.

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

```conf
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](https://github.com/hugosjoberg/blog-code/tree/main/vite-module-federation)
16 changes: 4 additions & 12 deletions hugo_stats.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
"video"
],
"classes": [
"...",
"2xl:bg-pink-200",
"2xl:block",
"2xl:hidden",
Expand All @@ -86,14 +85,8 @@
"btn-sm",
"capitalize",
"col-12",
"col-span-1",
"col-span-2",
"col-span-4",
"col-span-5",
"col-span-6",
"col-span-8",
"col-start-2",
"column",
"container",
"content",
"cursor-pointer",
Expand Down Expand Up @@ -133,13 +126,9 @@
"gallery",
"gallery-item",
"gallery-slider",
"gap-4",
"glightbox",
"grid",
"grid-cols-10",
"grid-cols-5",
"grid-cols-6",
"grid-container",
"gx-5",
"h-6",
"h2",
Expand Down Expand Up @@ -307,7 +296,6 @@
"top-0",
"top-[4px]",
"uppercase",
"w-5/12",
"w-[30px]",
"w-full",
"warning",
Expand Down Expand Up @@ -348,12 +336,14 @@
"heading-5",
"heading-6",
"hide-button",
"host",
"i-wanna-talk-about-the-assassination-attempt",
"image",
"implement-the-interface",
"learning-and-growth",
"link",
"message",
"micro-frontend",
"name",
"nav-menu",
"nav-toggle",
Expand All @@ -365,7 +355,9 @@
"project-structure",
"protection-of-personal--information",
"real-world-example",
"remote",
"responsibility-of-contributors",
"run-everything-together",
"search-modal-input",
"show-button",
"slider",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11208,27 +11208,12 @@ input#nav-toggle:checked ~ #nav-menu {
.order-3 {
order: 3;
}
.col-span-1 {
grid-column: span 1 / span 1;
}
.col-span-2 {
grid-column: span 2 / span 2;
}
.col-span-4 {
grid-column: span 4 / span 4;
}
.col-span-5 {
grid-column: span 5 / span 5;
}
.col-span-6 {
grid-column: span 6 / span 6;
}
.col-span-8 {
grid-column: span 8 / span 8;
}
.col-start-2 {
grid-column-start: 2;
}
.m-1 {
margin: 0.25rem;
}
Expand Down Expand Up @@ -11326,9 +11311,6 @@ input#nav-toggle:checked ~ #nav-menu {
.h-6 {
height: 1.5rem;
}
.w-5\/12 {
width: 41.666667%;
}
.w-\[30px\] {
width: 30px;
}
Expand All @@ -11344,12 +11326,6 @@ input#nav-toggle:checked ~ #nav-menu {
.grid-cols-10 {
grid-template-columns: repeat(10, minmax(0, 1fr));
}
.grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.grid-cols-6 {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.items-start {
align-items: flex-start;
}
Expand All @@ -11362,9 +11338,6 @@ input#nav-toggle:checked ~ #nav-menu {
.justify-between {
justify-content: space-between;
}
.gap-4 {
gap: 1rem;
}
.space-x-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.25rem * var(--tw-space-x-reverse));
Expand Down

0 comments on commit 6728219

Please sign in to comment.