You Don’t Need Another Library to Compose Micro Frontends at Run Time

One of the main advantages of building micro frontends is the independent deployments and releases. With build time composition, we can publish the micro frontend independently but can not release the app without being dependent on the other micro frontends. This leads to a modular monolith.

To overcome this problem, it is advisable to compose micro frontends at run time so that:

  • Any change in one micro frontend can be taken to production without worrying about other micro frontends aka Independent Deployments.
  • Each team is free to consider the tech choices within their micro frontend aka Autonomous Teams.
  • There is less coupling between the micro frontends and more cohesion within the micro frontend aka Modular Codebase.

There are multiple libraries like Webpack Module Federation, Single SPAs, and h-include available in the market to help the teams with run time micro frontends composition but then it is one more library to understand and manage instead of building the features.

Webpack modules federation has been the talk of the town since its launch as it has simplified micro frontend composition at run time. But with the emergence of faster bundlers like Vite, Turbopack, etc Webpack might not be the default choice for frontend applications anymore.

This article will discuss different patterns to compose micro frontends at run time without using any library or framework-specific technique.

1. Reverse Proxy Composition — Each application is an independent SPA

This composition technique is suitable when the whole page is a single micro frontend.

Taking the example of an e-commerce application, Catalog, Cart and User micro frontends can be deployed as three independently running applications on their web servers. But to make it work like a single seamless application, a proxy server is sitting in front of the end user to route it to the appropriate micro frontend according to the URL.

Reverse Proxy Composition
Reverse Proxy Composition

A simple node server working as a proxy may look something like this:

const catalogServer = "https://catalog.myapp.com",
cartServer = "https://cart.myapp.com",
userServer = "https://user.myapp.com";

function match(domain) {
return proxy(domain, {
proxyReqPathResolver(req) {
console.log(`${domain}${req.url}`);
return `${domain}${req.url}`;
}
});
}

server.use("/catalog", match(catalogServer));

server.use("/cart", match(cartServer));

server.use("/user", match(userServer));

server.listen(3000, (err) => {
if (err) throw err;
console.log(`> Ready on http://myapp.com`);
});

Pros / Use Cases

  • Convenient technique for a project re-platforming to new technology. That also means each team can choose a different UI framework although not always recommended.
  • Go to choice for Server Side rendering as each micro frontend can be an independent SSR application.
  • Easy to manage as you only need an anchor tag to route to another micro frontend.
  • There is no need for a container application, unlike build time composition.

Cons

  • Only suitable when the whole page is a single micro frontend.
  • There will be full page reloads to navigate from one micro frontend to another which can cause delays in the largest contentful paint. The routes within the same micro frontend can continue to work as a single-page app.
  • The page layout might not remain consistent as each micro frontend need to handle the layout individually or by sharing a library.
  • One more additional layer is needed for the reverse proxy server in the overall application architecture.

Please check this github repo for the complete example of reverse proxy composition.

2. Composition by lazy loading the micro frontends bundled using JavaScript

This composition uses the vanilla JavaScript way to dynamically add a new script tag to load the micro frontend.

container based composition using javascript to render different micro frontends
Container-based composition

Let’s try to discuss the technique by applying it to two different scenarios

2a. When each page is a different micro frontend

In this case, we need a container application that would be responsible to route to different pages and then each page internally can render the micro frontend. The same container app can hold the layout for the overall app as well.

Using react-router, the container app routes for Catalog and Cart micro frontends would be:

<Routes>
<Route path='/products' element={<Catalog />} />
<Route path='/cart' element={<Cart />} />
</Routes>

and the catalog page component inside the container app can download and render the catalog micro frontend as:

export default function Catalog() {
const ref = useRef(null);

const renderMicrofrontend = () => {
window.mountCatalogMfe(ref.current);
}

useEffect(() => {
if (window && document && !document.getElementById('app-catalog')) {
const script = document.createElement('script');
script.id = 'app-catalog';
script.src = 'url for the catalog micro frontend';
script.onload = renderMicrofrontend;
document.head.appendChild(script);
} else {
renderMicrofrontend();
}
}, []);

return (
<div ref={ref} />
)
}

The IF condition checking document.getElementById(‘app-catalog’) will make sure that the same micro frontend src is not getting downloaded when the user navigates back to the same page.

Inside the Catalog micro frontend, we have to make sure that we are exposing a method to render the micro frontend on the window object.

window.mountCatalogMfe = (el) => {
ReactDOM.render(
<CatalogApp />,
el
)
}

Now, we can use the same code to actually render the different micro frontends on different routes or even create a library for that.

Please check this github repo for the complete example of container based composition technique

2b. Multiple micro frontends in a single screen

Consider the example for a product details page where we can easily identify components from different domains rendered inside a single page.

Product Details Page

Using the same technique we discussed above, we can render the Review as a micro frontend inside the product details page directly instead of a route change.

Pros / Use Cases

  • A pure JavaScript-based framework solution to compose micro frontend at run time.
  • No full-page reloading as the whole application behaves like a seamless single-page app.
  • No need for an additional server to route to the appropriate micro frontend.

Cons

  • In the case of each screen as a different micro frontend, we need a container application that would render the micro frontend on route change.
  • We will end up downloading duplicate dependencies for each micro frontend but it can be resolved using something like webpack externals and then using the script tag to download those dependencies from cdn.
  • Since each micro frontend should run independently also, we need to create two entry points in the configuration. One for the dev server to use and the other for the production build to expose a method on the window object.
entry: {
main: './src/index.js',
dev: './src/dev-root.js',
},
output: {
filename: '[name].js',
}

dev-root.js

ReactDOM.render(
<App />,
document.querySelector('#catalog-root')
);

index.js

window.mountCatalogMfe = (el) => {
ReactDOM.render(
<CatalogApp />,
el
)
}

Please check this github repo for the complete example of container based composition technique

It’s worth mentioning that one can also use iFrames or even web components to compose the micro frontends at run time as long as cross microfrontend communication, authentication, performance, acessibility etc. requirements are taken care of. So always make sure that you have understood the functional requirements before deciding on the composition pattern.

To understand which micro frontend communication technique can suit the composition patterns discussed above, check out the article on 5 different techniques for cross micro frontend communication.

💡 Note: Micro frontends are easier when you can apply a component-driven development approach to them. Bit makes this easier by providing an integrated dev environment (compiler, tester, linter, documentation, CI, dev server, and packaging/dependency management/bundler all-in-one) for building apps. Learn more here.

Build Micro frontends with reusable components

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

Learn more:


You Don’t Need Another Library to Compose Micro Frontends at Run Time was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Vishal Sharma

One of the main advantages of building micro frontends is the independent deployments and releases. With build time composition, we can publish the micro frontend independently but can not release the app without being dependent on the other micro frontends. This leads to a modular monolith.

To overcome this problem, it is advisable to compose micro frontends at run time so that:

  • Any change in one micro frontend can be taken to production without worrying about other micro frontends aka Independent Deployments.
  • Each team is free to consider the tech choices within their micro frontend aka Autonomous Teams.
  • There is less coupling between the micro frontends and more cohesion within the micro frontend aka Modular Codebase.

There are multiple libraries like Webpack Module Federation, Single SPAs, and h-include available in the market to help the teams with run time micro frontends composition but then it is one more library to understand and manage instead of building the features.

Webpack modules federation has been the talk of the town since its launch as it has simplified micro frontend composition at run time. But with the emergence of faster bundlers like Vite, Turbopack, etc Webpack might not be the default choice for frontend applications anymore.

This article will discuss different patterns to compose micro frontends at run time without using any library or framework-specific technique.

1. Reverse Proxy Composition — Each application is an independent SPA

This composition technique is suitable when the whole page is a single micro frontend.

Taking the example of an e-commerce application, Catalog, Cart and User micro frontends can be deployed as three independently running applications on their web servers. But to make it work like a single seamless application, a proxy server is sitting in front of the end user to route it to the appropriate micro frontend according to the URL.

Reverse Proxy Composition
Reverse Proxy Composition

A simple node server working as a proxy may look something like this:

const catalogServer = "https://catalog.myapp.com",
cartServer = "https://cart.myapp.com",
userServer = "https://user.myapp.com";

function match(domain) {
return proxy(domain, {
proxyReqPathResolver(req) {
console.log(`${domain}${req.url}`);
return `${domain}${req.url}`;
}
});
}

server.use("/catalog", match(catalogServer));

server.use("/cart", match(cartServer));

server.use("/user", match(userServer));

server.listen(3000, (err) => {
if (err) throw err;
console.log(`> Ready on http://myapp.com`);
});

Pros / Use Cases

  • Convenient technique for a project re-platforming to new technology. That also means each team can choose a different UI framework although not always recommended.
  • Go to choice for Server Side rendering as each micro frontend can be an independent SSR application.
  • Easy to manage as you only need an anchor tag to route to another micro frontend.
  • There is no need for a container application, unlike build time composition.

Cons

  • Only suitable when the whole page is a single micro frontend.
  • There will be full page reloads to navigate from one micro frontend to another which can cause delays in the largest contentful paint. The routes within the same micro frontend can continue to work as a single-page app.
  • The page layout might not remain consistent as each micro frontend need to handle the layout individually or by sharing a library.
  • One more additional layer is needed for the reverse proxy server in the overall application architecture.
Please check this github repo for the complete example of reverse proxy composition.

2. Composition by lazy loading the micro frontends bundled using JavaScript

This composition uses the vanilla JavaScript way to dynamically add a new script tag to load the micro frontend.

container based composition using javascript to render different micro frontends
Container-based composition

Let's try to discuss the technique by applying it to two different scenarios

2a. When each page is a different micro frontend

In this case, we need a container application that would be responsible to route to different pages and then each page internally can render the micro frontend. The same container app can hold the layout for the overall app as well.

Using react-router, the container app routes for Catalog and Cart micro frontends would be:

<Routes>
<Route path='/products' element={<Catalog />} />
<Route path='/cart' element={<Cart />} />
</Routes>

and the catalog page component inside the container app can download and render the catalog micro frontend as:

export default function Catalog() {
const ref = useRef(null);

const renderMicrofrontend = () => {
window.mountCatalogMfe(ref.current);
}

useEffect(() => {
if (window && document && !document.getElementById('app-catalog')) {
const script = document.createElement('script');
script.id = 'app-catalog';
script.src = 'url for the catalog micro frontend';
script.onload = renderMicrofrontend;
document.head.appendChild(script);
} else {
renderMicrofrontend();
}
}, []);

return (
<div ref={ref} />
)
}

The IF condition checking document.getElementById('app-catalog') will make sure that the same micro frontend src is not getting downloaded when the user navigates back to the same page.

Inside the Catalog micro frontend, we have to make sure that we are exposing a method to render the micro frontend on the window object.

window.mountCatalogMfe = (el) => {
ReactDOM.render(
<CatalogApp />,
el
)
}

Now, we can use the same code to actually render the different micro frontends on different routes or even create a library for that.

Please check this github repo for the complete example of container based composition technique

2b. Multiple micro frontends in a single screen

Consider the example for a product details page where we can easily identify components from different domains rendered inside a single page.

Product Details Page

Using the same technique we discussed above, we can render the Review as a micro frontend inside the product details page directly instead of a route change.

Pros / Use Cases

  • A pure JavaScript-based framework solution to compose micro frontend at run time.
  • No full-page reloading as the whole application behaves like a seamless single-page app.
  • No need for an additional server to route to the appropriate micro frontend.

Cons

  • In the case of each screen as a different micro frontend, we need a container application that would render the micro frontend on route change.
  • We will end up downloading duplicate dependencies for each micro frontend but it can be resolved using something like webpack externals and then using the script tag to download those dependencies from cdn.
  • Since each micro frontend should run independently also, we need to create two entry points in the configuration. One for the dev server to use and the other for the production build to expose a method on the window object.
entry: {
main: './src/index.js',
dev: './src/dev-root.js',
},
output: {
filename: '[name].js',
}

dev-root.js

ReactDOM.render(
<App />,
document.querySelector('#catalog-root')
);

index.js

window.mountCatalogMfe = (el) => {
ReactDOM.render(
<CatalogApp />,
el
)
}
Please check this github repo for the complete example of container based composition technique

It’s worth mentioning that one can also use iFrames or even web components to compose the micro frontends at run time as long as cross microfrontend communication, authentication, performance, acessibility etc. requirements are taken care of. So always make sure that you have understood the functional requirements before deciding on the composition pattern.

To understand which micro frontend communication technique can suit the composition patterns discussed above, check out the article on 5 different techniques for cross micro frontend communication.

💡 Note: Micro frontends are easier when you can apply a component-driven development approach to them. Bit makes this easier by providing an integrated dev environment (compiler, tester, linter, documentation, CI, dev server, and packaging/dependency management/bundler all-in-one) for building apps. Learn more here.

Build Micro frontends with reusable components

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

Learn more:


You Don't Need Another Library to Compose Micro Frontends at Run Time was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Vishal Sharma


Print Share Comment Cite Upload Translate Updates
APA

Vishal Sharma | Sciencx (2023-04-11T04:53:00+00:00) You Don’t Need Another Library to Compose Micro Frontends at Run Time. Retrieved from https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/

MLA
" » You Don’t Need Another Library to Compose Micro Frontends at Run Time." Vishal Sharma | Sciencx - Tuesday April 11, 2023, https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/
HARVARD
Vishal Sharma | Sciencx Tuesday April 11, 2023 » You Don’t Need Another Library to Compose Micro Frontends at Run Time., viewed ,<https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/>
VANCOUVER
Vishal Sharma | Sciencx - » You Don’t Need Another Library to Compose Micro Frontends at Run Time. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/
CHICAGO
" » You Don’t Need Another Library to Compose Micro Frontends at Run Time." Vishal Sharma | Sciencx - Accessed . https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/
IEEE
" » You Don’t Need Another Library to Compose Micro Frontends at Run Time." Vishal Sharma | Sciencx [Online]. Available: https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/. [Accessed: ]
rf:citation
» You Don’t Need Another Library to Compose Micro Frontends at Run Time | Vishal Sharma | Sciencx | https://www.scien.cx/2023/04/11/you-dont-need-another-library-to-compose-micro-frontends-at-run-time/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.