FynMesh + federation-js at a glance

FynMesh Features

Independently built FynApps run together on one page and share code at runtime through Module Federation. Here is each feature, one picture at a time.

Same app, multiple versions

Ship every version. Let each app pick.

Publish fynapp-x1 2.0 next to 1.0. Apps built against 1.x keep getting 1.x. Nobody renames anything or edits a URL.

fynapp-2-react18 fynapp-x1 ^1.0.0 fynapp-1 fynapp-x1 ^2.0.0 fynapp-1-b fynapp-x1 ^2.0.0 fynapp-x1 1.0.0 fynapp-x1 2.0.0 ^1.0.0 ^2.0.0 ^2.0.0 one page · one name · two majors
import("fynapp-x1/main", { with: { type: "mf-expose", semver: "^2.0.0" } })
The consumer writes a range in its import. The page picks the loaded version that fits it.

Join by Loading

Load an app and it joins the page's shared scope. No app lists its peers. Apps that land together share code automatically. See federation-js.

fynapp-6-react React 19 fynapp-4-vue Vue 3 fynapp-8-svelte Svelte fynapp-2-react18 React 18 load load load load share scope: fynmesh react 19.1.0 react-dom 19.1.0 react 18.3.1 vue 3 each app adds what it ships · each import takes a fit
Joining is part of loading. There is no second step and no peer list to maintain.

Semver Sharing

React 18 and React 19 apps run on the same page. Apps whose ranges agree share one copy. A new major gets its own. The semver sharing guide has the details.

fynapp-2-react18 fynapp-1 fynapp-6-react fynapp-notes react 18.3.1 1 copy · 1 app react 19.1.0 1 copy · 3 apps ^18 ^19 ^19 ^19
Each import carries its own range. The loader matches it against what the page already holds.

Framework Agnostic

Six frameworks on one loader. There are no bridges or adapters. Each app is a plain federated container.

React fynapp-6-react Vue fynapp-4-vue Preact fynapp-5-preact Solid fynapp-7-solid Svelte fynapp-8-svelte Marko fynapp-3-marko one loader · SystemJS + federation-js
All six run together in the live demo.

Legacy RequireJS Bundles

Federated modules serve legacy webpack AMD bundles as RequireJS modules. The bundles are not rebuilt, and they can move to a new React major in stages.

Team A bundle webpack AMD, not rebuilt Team B bundle webpack AMD, not rebuilt Team C bundle webpack AMD, not rebuilt RequireJS · define(["react", "react-dom", "ui-kit"]) AMD add-on · CWP FynApp serves the same ids from federation
One set of widgets runs on the old React 18 bundle and one on React 19 from federation in the legacy RequireJS demo.

Dependency-Ordered Boot

Ask for one app by name. The kernel reads manifests, builds the dependency graph, and boots providers before consumers. See the kernel docs.

BATCH 1 BATCH 2 fynapp-x1 1.0.0 fynapp-x1 2.0.0 fynapp-react-middleware fynapp-2-react18 fynapp-1 fynapp-6-react boots before
Cycles are detected. Each batch loads with bounded concurrency.

FynUnit Lifecycle

Each app's FynUnit can initialize, execute, suspend, resume and shut down. The kernel tracks which state every app is in.

bootstrapping mounted suspended failed shutdown execute suspend resume throws shutdown
State is keyed by name@version, so two versions of one app keep separate lifecycles.

FynMesh Middleware

One app provides a capability. Others declare useMiddleware and get its API. The demo's design tokens, shell layout and shared counter all work this way.

fynapp-react-middleware basic-counter kernel middleware layer fynapp-2-react18 React 18 fynapp-6-react React 19 registers same API
A React 18 app and a React 19 app share one counter.

FynBus

Apps send messages and ask each other questions. The platform stamps who sent each message. It also drops an app's subscriptions when that app shuts down.

fynapp-2-react18 React 18 emit demo-chat request get-status gets the reply FynBus sender stamped fynapp-1 React 19 on demo-chat handle get-status message request reply
Both apps chat and answer requests in the live demo. Apps don't hear their own messages unless they ask to.

Federation Inspector

One call shows what the page holds. You see every shared module, its version, and who provides it. The demo has an in-page inspector too. Read the inspector docs.

Example rows. The real snapshot comes from the live registry.

Combined Bundles

Many small modules ship in one file. Each module still acts like its own file. It keeps its URL and runs only when something imports it. The rollup plugin builds them.

3 FILES · 3 REQUESTS hello.js banner.js getInfo.js federation-combine 1 FILE · 1 REQUEST combo.js hello.js ran banner.js ran getInfo.js registered, not run each module keeps its own URL
federation-combine dist
It runs after the build, so it can repack apps you didn't build. The first import of any member pulls the whole file. If the map is stale, the loader fetches the module's own file instead.

Small Footprint

The federation layer is under 9 KB gzip. The page loads it once, and every app uses it. See federation-js.

loader system 3.8 federation-js 4.9 8.7 KB kernel browser kernel 9.7 KB 0 2 4 6 8 KB
Minified with esbuild, gzip level 9.
  • Embedded manifest. Each app's manifest rides inside its entry file, so one request brings both.

Also built in

MiddlewareStateRegistry

Scoped, reactive shared state for middleware. An app that loads late still sees the current value.

KernelTelemetry

Load and lifecycle events in a bounded ring buffer. Send them anywhere with a pluggable transport.

Dev error overlay

Development builds show a FynApp's bootstrap failure right on the page.

create-fynapp and cfa

Scaffold a new FynApp, then build and check it from the command line.

Start a FynApp

fyn global add create-fynapp
create-fynapp