Skip to content

Module Federation

Tourism Suite is a host (the shell) that loads micro frontends at runtime with @module-federation/vite. The library must be loaded once and reused by every remote, like React itself. Three things make that work.

Add @beyul/sulmu-ui to the shared list of the host and of every remote. In the frontend this list is built once in packages/configs/vite/index.mjs and used by both:

// Loaded once by the shell and reused by every remote.
const SHARED = Object.fromEntries(
[
'react',
'react-dom',
// ...
'@beyul/sulmu-ui',
].map((name) => [name, { singleton: true }]),
)
federation({ name: 'shell', remotes, shared: SHARED })

The host and every remote that imports the library also list it in their own package.json, with the same version range.

It is tempting to add @ark-ui/react to the list as well. Do not:

  • The library imports Ark by subpath (@ark-ui/react/dialog, @ark-ui/react/field). A shared entry for @ark-ui/react matches none of those imports, so it would share nothing.
  • Chakra UI pins its own version of Ark, which differs from the library’s. Forcing a singleton would hand one of them the wrong version.

Ark travels inside the shared library chunk. Sharing the library is what keeps Ark to one copy.

3. Import the stylesheet once, in the host

Section titled “3. Import the stylesheet once, in the host”
apps/shell/src/index.tsx
import '@beyul/sulmu-ui/styles.css'

Remotes do not import it. The stylesheet has every variant of every component, so a remote can use any component without shipping CSS of its own. The font is loaded by the host too.

For dark mode, set data-theme on <html> in the host; it applies to every remote and to popups rendered at the end of <body>.

In the browser, with the host and a remote running, open the console and look at the share scope:

__FEDERATION__.__SHARE__

There should be one entry for @beyul/sulmu-ui, provided by the shell and used by the remote. If a remote provides its own copy, its version range does not match the host’s.

A singleton means one version at runtime: the host’s. When the library is upgraded, upgrade the host and the remotes together, and deploy the host no later than the remotes. A remote built against a newer minor version than the host provides can fail at runtime on a component or prop that the host’s copy does not have.