Skip to content

RFC: Layer-aware Module Federation #15573

Description

@ScriptedAlchemy

RFC: Layer-aware Module Federation

Summary

Make Module Federation 1.5 respect Rspack layers when sharing dependencies, exposing modules, and generating manifests. A shared package can have separate server and client variants without giving each variant an unrelated shared key.

Motivation

Layers already distinguish module builds, but federation must carry that distinction through resolution, runtime initialization, tree-shaking, and metadata. Losing it can select the wrong implementation or attribute exports and assets to the wrong variant.

flowchart LR
  S["Server-layer importer"] --> SS["Shared package · server layer"]
  C["Client-layer importer"] --> CS["Shared package · client layer"]
  SS --> SM["Server provider or local fallback"]
  CS --> CM["Client provider or local fallback"]
Loading

The package name can be the same; the shared identities remain distinct.

Proposal

Option Meaning
shared.request Import request to match; defaults to the configuration key.
shared.shareKey Key used for sharing; independent of the matched request.
shared.issuerLayer Restrict which importing layer consumes this configuration.
shared.layer Select the provider and local fallback's module layer.
exposes[key].layer Build that exposed module in a specific layer.
shareScope Sharing namespace, or an ordered array such as ['app', 'default'] in enhanced mode.

For example, expose one module in two layers and share an example package separately in each:

const { container } = require('@rspack/core');

module.exports = {
  experiments: { layers: true },
  plugins: [
    new container.ModuleFederationPlugin({
      name: 'app',
      exposes: {
        './server': { import: './src/view.js', layer: 'server' },
        './client': { import: './src/view.js', layer: 'client' },
      },
      shared: [
        { 'ui-runtime': { issuerLayer: 'server', layer: 'server' } },
        { 'ui-runtime': { issuerLayer: 'client', layer: 'client' } },
      ],
    }),
  ],
};

Matching layer configurations take precedence over unlayered fallbacks. An omitted layer and layer: '' remain distinct.

Ordered shareScope arrays retain their order through runtime initialization. Initial ordered consumers wait for initialization; existing scalar eager consumers remain synchronous. Scope order does not replace version or loading strategy.

Manifests retain existing fields and add layer/scope identity and expose requirements. An optional providers array preserves version, import, and assets when one identity has multiple concrete providers. Export usage and fallback assets stay associated with the correct identity.

Compatibility and scope

  • Layer options require the enhanced runtime (Module Federation 1.5); legacy configurations retain their behavior.
  • Existing unlayered manifests remain usable by older readers. Layer-aware readers need coordinated support.

Trade-offs

Using separate share keys or builds avoids this extension, but forces applications to encode layer identity themselves. Carrying it through federation keeps configuration consistent with Rspack's module graph, at the cost of more runtime/metadata bookkeeping and some binding-size growth.

Delivery and review

The implementation is one ordered stack:

  1. #12977: shared matching and identity.
  2. #14911: ordered-scope runtime initialization.
  3. #14912: layered exposes and integration coverage.
  4. #14913: manifest metadata.

Reader/types coordination: module-federation/core#5039.

Review should verify layer isolation, exact versus unlayered matching, ordered startup, provider/export attribution, and unchanged legacy behavior. Feedback requested: are the option boundaries and additive metadata sufficient for other layer-based integrations?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions