Shared Libraries
Motivation
If many microfrontends are built using the same frameworks and libraries it becomes inefficient to bundle these libraries with every microfrontend. Users would end up loading the same library code multiple times which unnecessarily increases loading times of microfrontends and requires more server ressources due to increased data transfer.
Therefore, as soon as multiple microfrontends agree on a common tech stack their heavy libraries should be provided by host applications or some external CDN.
External Dependencies in Microfrontends
Microfrontends must declare shared libraries as external ressources in the configuration of their bundler.
- Vite configuration must include
build.rollupOptions
with anexternal
property. For UMD/IIFE bundles the names of global variables must be defined inbuild.rollupOptions.output.globals
. There is a good example in the Library Mode documentation. - Webpack configuration must include
externals
. Names of global variables for UMD/IIFE bundles are defined there as well.
Example for Vite and React:
import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
import { defineConfig } from "vite";
export default defineConfig(({ mode }) => ({
plugins: [react()],
define: { "process.env.NODE_ENV": JSON.stringify(mode) },
build: {
lib: {
entry: resolve(__dirname, "./src/main.tsx"),
name: "ServiceMFE",
fileName: "service-mfe",
},
rollupOptions: {
/**
* 1. Declare module specifiers of shared libraries.
*/
external: ["react", "react-dom"],
output: {
/**
* 2. For UMD bundle specify global variable names for shared libraries.
* Make sure these names match the ones exposed by the libraries!
*/
globals: {
react: "React",
"react-dom": "ReactDOM",
},
},
},
},
}));
This project template provides a configuration in the file apps/service-mfe/vite.config.ts
.
Import Maps in Host Applications using ES Modules
Host applications which import ES module bundles of microfrontends using dynamic import must define an import map which specifies the URLs for bare module specifiers of shared libraries.
Example for React:
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.2.0",
"react-dom": "https://esm.sh/react-dom@18.2.0"
}
}
</script>
This project template provides a React component in the file apps/host-nextjs/src/components/importmap.tsx
.
Global Variables in Host Applications using UMD Bundles
Host applications which load UMD/IIFE bundles of microfrontends must include <script>
tags to load UMD/IIFE versions of shared libraries before loading any microfrontend modules.
Example for React:
<html lang="en">
<head>
<script
src="https://unpkg.com/react@18.2.0/umd/react.production.min.js"
defer
></script>
<script
src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.production.min.js"
defer
></script>
</head>
<body>
<!-- ... -->
<script
src="https://my-service.my-company.com/mfe-module.umd.cjs"
onload="mountMFE()"
onerror="showError()"
defer
></script>
</body>
</html>
This project template provides an implementation in the file apps/host-express/views/service.ejs
.