Mastering Module Federation: From NPM Sharing to Advanced Remote Loading
This article explains how to share UI modules via NPM packages and Module Federation, compares traditional iframe approaches, dives into low‑level and high‑level concepts, demonstrates practical webpack configurations, version‑selection strategies, and runtime loading mechanisms with detailed code examples.
Introduction
In real projects we often need to share UI components across multiple applications. The most common practice is to publish the component as an NPM package and import it via package.json. However, when many projects depend on the same component, manual updates become painful.
NPM‑based Sharing
We can package a carousel component as an NPM module, add it to dependencies, and let each host project compile it. This works for simple cases but fails when a shared module must be updated simultaneously across all consumers.
Module Federation – Share Sub‑App
Traditional micro‑frontend solutions use iframe which brings communication, SEO, caching, and performance issues. Module Federation allows independent builds to expose and consume modules at runtime without hard dependencies.
Let’s explore the design through configuration examples.
Low‑level Concepts – Local and Remote Modules
The diagram likens a host’s local module to a molecule (container) and a remote module to an atom (shared piece). Each host treats its own code as a molecule, while the remote code is an atom that can be loaded asynchronously.
Each Host sees its own code as a local module (molecule).
Each Remote is a remote module (atom) loaded at runtime.
A container is created through a container entry, exposing asynchronous access to specific modules. The access is split into two steps: Loading the module (asynchronous) Evaluating the module (synchronous)
High‑level Concepts – Bidirectional Sharing and Inference
When two projects need to share functionality, copying code leads to duplicated updates. Module Federation solves this by allowing both sides to expose and consume each other’s modules.
Example: Regular MF Usage
new ModuleFederationPlugin({
name: "app1",
remotes: { app2: `app2@${getRemoteEntryUrl(3002)}` },
});
new ModuleFederationPlugin({
name: "app2",
filename: "remoteEntry.js",
exposes: { "./ButtonContainer": "./src/ButtonContainer" },
remotes: { app3: `app3@${getRemoteEntryUrl(3003)}` },
});
new ModuleFederationPlugin({
name: "app3",
filename: "remoteEntry.js",
exposes: { "./Button": "./src/Button" },
});Loading Module Code
// Simplified excerpt of the runtime loader
var moduleMap = { "./Button": () => Promise.all([__webpack_require__.e("webpack_sharing_consume_default_react_react-_0085"), __webpack_require__.e("src_Button_js")]).then(() => __webpack_require__("./src/Button.js")) };
function get(module, getScope) { /* … */ }
function init(shareScope, initScope) { /* … */ }
__webpack_require__.d(exports, { get: () => get, init: () => init });Version Selection
Using singleton: true shares a single instance of a package. When hosts require different versions, Module Federation picks the highest compatible version unless requiredVersion is set to false to disable inference.
// Host package.json
"dependencies": { "mf-test-ssy": "^1.0.0" }
// Remote package.json
"dependencies": { "mf-test-ssy": "^2.0.0" }
new ModuleFederationPlugin({
shared: {
react: { singleton: true },
"react-dom": { singleton: true },
"mf-test-ssy": { singleton: true },
},
});Experiments show that the remote with the higher version is used when the host’s version is lower, while the opposite direction keeps the host’s version.
Automatic Inference Settings
The packageName option lets you specify which package to look up. By default Module Federation infers the request; setting requiredVersion: false disables this behavior.
Scope and Runtime Sharing
The runtime creates a shared scope object ( __webpack_require__.S) and registers each shared module with its version, eager flag, and source. The SharePlugin generates ConsumeSharedPlugin and ProvideSharedPlugin configurations that handle the actual loading and initialization.
class SharePlugin {
constructor(options) {
const sharedOptions = parseOptions(...);
this._shareScope = options.shareScope;
this._consumes = /* … */;
this._provides = /* … */;
}
apply(compiler) {
new ConsumeSharedPlugin({ shareScope: this._shareScope, consumes: this._consumes }).apply(compiler);
new ProvideSharedPlugin({ shareScope: this._shareScope, provides: this._provides }).apply(compiler);
}
}
module.exports = SharePlugin;Conclusion
Module Federation treats shared modules as atoms that can be loaded on demand, while local modules act as molecules that compose the application. Using shared scopes, version inference, and singleton settings, developers can avoid duplicated updates and achieve efficient, runtime‑driven code sharing across micro‑frontends.
Other MF Ecosystem
ExternalTemplateRemotesPlugin
For dynamic remote URLs and cache invalidation, the plugin allows runtime URL substitution.
new ModuleFederationPlugin({
remotes: { 'my-remote-1': 'my-remote-1@[window.remote-1-domain]/remoteEntry.js?[getRandomString()]' }
}),
new ExternalTemplateRemotesPlugin();References
https://webpack.js.org/concepts/module-federation/#building-blocks
https://github.com/sokra/slides/blob/master/content/ModuleFederationWebpack5.md
https://www.youtube.com/watch?v=x22F4hSdZJM
https://github.com/module-federation/module-federation-examples
https://segmentfault.com/a/1190000039031505
http://img.iamparadox.club/img/mf2.jpg
https://developer.aliyun.com/article/755252
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
WeDoctor Frontend Technology
Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
