federation-js
v1.1.4
Published
Runtime for JavaScript module federation, built on a SystemJS-style module registry
Maintainers
Readme
federation-js
Runtime for JavaScript module federation, built on a SystemJS-style module registry.
FynMesh: Website · Demo · Shell demo
This is the piece that runs in the browser. It resolves shared modules across independently built and deployed bundles, keeps a single instance of a shared dependency when asked to, and lets one bundle load modules exposed by another.
Containers are normally generated for you by
rollup-plugin-federation — you rarely construct one by hand.
Install
npm install federation-jsThe module loader
federation-js is half of a pair. It does not carry a module registry of its own — it expects a
System global, and it must be the fork of SystemJS this package ships, not stock SystemJS.
The fork keeps the module registry, name→url, url→module and per-version qualifiers in
System.registrations; stock SystemJS has no such thing, and a crossed pair fails in ways that
look like federation bugs.
Both loader builds are in this package's dist, so load one before the runtime:
<!-- development: readable, keeps the long-form diagnostics -->
<script src="/node_modules/federation-js/dist/system.js"></script>
<script src="/node_modules/federation-js/dist/federation-js.dev.js"></script><!-- production -->
<script src="/node_modules/federation-js/dist/system.min.js"></script>
<script src="/node_modules/federation-js/dist/federation-js.min.js"></script>Keep the two halves on the same build: system.js with federation-js.dev.js, system.min.js
with federation-js.min.js.
Runtime
Importing the runtime installs a Federation instance on the global object:
import "federation-js/runtime";
// load a container and pull an exposed module out of it
Federation.import("__mf_container_plugin_1")
.then((container) => container.get("./bootstrap"))
.then((getModule) => console.log("module", getModule()));A shared module is retrieved the same way, by the name it was shared under:
Federation.import("__mf_container_plugin_1")
.then((container) => container.get("react"))
.then((getModule) => console.log("module", getModule()));A container that only consumes a shared module can still resolve it, provided some container that shares it has already loaded.
Debugging a minified page
Federation.__I() returns a snapshot of what the runtime decided about shared-module
resolution: for every chunk and share key, the importer-declared ranges, the ranges
resolution actually applied, and the versions this runtime's own semver accepts. It is in
the minified build too — that is the build it exists for, since the same information is
readable off $SS and $SC in a development one. The result is a versioned envelope,
{ v: 1, r: [...] }; check v before reading the rest.
The name is __I because nobody guesses it, which is the intent: it is a debugging hatch,
not part of the API a container or the loader talks to.
Combined module files
Several modules can be shipped in one physical file. Each still registers itself under its own
filename, so nothing about importing it changes — the file it arrived in is not part of its
identity. A module built into a combined file carries b (the physical file) alongside f
(itself); when they differ, the runtime derives the module's own url from f rather than from
document.currentScript, which would otherwise be the same for every module in the file.
Two ways a combined file gets used:
- Already loaded — a plain
<script>tag is enough. Every module in it registers, and a later import of any of them resolves without a request. - Not loaded yet — the container entry declares which file carries which modules
(
Federation._B(map, container, version)), and the first import of any member pulls that file once, however many members ask at the same time. If the file turns out not to carry the module it claimed, the runtime warns and loads that module's own file instead.
Pulling a file registers its modules; it does not execute them. A module's body still runs on first import, exactly once.
Producing these files is a build concern — see rollup-plugin-federation's
federation-combine.
Entry points
| Import | Contents |
| --- | --- |
| federation-js | Container class and the public types |
| federation-js/runtime | the runtime; installs the global Federation |
| federation-js/container | Container on its own |
| federation-js/types | types on their own |
Shared-module resolution is semver aware: a container declares the range it accepts, and the runtime picks a loaded version that satisfies it, falling back to loading its own copy when nothing matches.
License
Apache-2.0
