Skip to content

feat(enhanced): align Webpack and Rspack layer support - #5039

Draft
ScriptedAlchemy wants to merge 34 commits into
codex/manifest-graph-foundationfrom
feat/rspack-layered-shared-metadata
Draft

ScriptedAlchemy wants to merge 34 commits into
codex/manifest-graph-foundationfrom
feat/rspack-layered-shared-metadata

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

Description

Let enhanced Webpack expose modules in a named layer, and preserve expose and shared layers in Webpack and Rspack manifests. A remote can build separate variants of the same source:

new ModuleFederationPlugin({
  name: 'remote',
  exposes: {
    './server': { import: './src/component', layer: 'server' },
    './client': { import: './src/component', layer: 'client' },
  },
});

Module rules retain precedence. Omitting layer preserves existing behavior; an empty expose-layer string is rejected.

Layer-specific relative shared requests now match by issuer layer and resolve their fallback from the importing module's directory. Manifest entries retain public expose aliases, shared requirements, and assets when chunks merge, exposes have multiple imports, or asset analysis is disabled. Unlayered shared IDs stay unchanged; no public identityId field is added.

At runtime, providers with the same scope, key, and version stay separate by layer. Lookup prefers the requested layer and uses an unlayered provider only when that layer is absent. Registration, singleton/version selection, remote cleanup, and snapshot asset matching follow that identity. Unlayered share-scope entries retain their existing format for older runtimes.

Review order

  1. Expose options, generated schemas, container dependencies, and cache serialization.
  2. Shared-request matching and relative fallback resolution.
  3. Layer-specific graph collection and native Rspack manifest post-processing.
  4. Fixture, cache, reader-compatibility, and cross-bundler tests.

The generic Webpack graph collector and rollback option belong to the base PR, Collect Webpack stats from the compilation graph. Native Rspack still collects its data in Rust.

Verification

Latest local checks passed: runtime-core (141), SDK (70; one existing skip), bundler runtime (103), 18 Webpack layer/scalar-scope config cases, and 20 manifest-reader compatibility tests. The affected dependency builds and normal commit hooks passed.

Actual Federation 0.24.1 and 2.9.1 constructors pass 26 no-layer compatibility assertions in both host directions, including async factories, singleton/version selection, and mixed layered-provider/local-fallback behavior. The final Rspack adapter passes four same-scope/key/version layer cases across both registration orders and sync/async loading. The earlier ee3f65a runtime head passed hosted formatting, package builds, publishing checks, affected tests, and Node.js 20 verification. Final-head validation is tracked below.

Layered scope metadata transfers by reference; JSON or copying a scope does not preserve it. Unrelated full app/Metro/release suites were not run.

Related Issue

Layer-aware federation RFC.

Same-version shared modules across scopes is a separate follow-up. Provider metadata is not part of this stack; it has its own RFC and independent draft.

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix
  • New feature

Checklist

  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have updated the documentation.

The compiler compatibility fixture pins Rspack 1.3.9/Federation 0.13.1 as the older host and the published final Rspack d538c9c preview (2.2.7) with the current workspace runtime as the remote. All four old-host cases pass locally across default/custom scopes and remote-entry/manifest loading. The complete manifest suite passes 55/55 tests. The final published c4521e5 Federation suite (2.9.2) passes four actual native same-scope/key/version layer cases, both provider orders and eager/lazy loading, plus four sync/async adapter cases, 26 assertions with actual Federation 0.24.1/2.9.1, and two classic share-entry checks. Both Linux x64 and Mac ARM64 compiler preview workflows succeeded. Both final core heads pass hosted formatting, package builds, publishing checks, and affected package tests; Node.js 20 also passes on both heads; broader E2E jobs remain pending. The two shared preview checksums were refreshed after the Mac publication; an empty-store frozen installation verifies the compiler, wrapper, and Linux binary.

Two sync/async regressions cover compiler-provided share entries without enhanced shareConfig. The seven formerly failing legacy config cases and two provider cases pass locally after the one-line compatibility fix.

Rspack's layer-aware Module Federation stack (web-infra-dev/rspack#12977,
#14912, #14913) changes what the public v2 wrapper receives:

- ContainerManager.containerPluginExposesOptions rebuilt exposes from
  import/name only and dropped exposes.*.layer, so a layered expose was
  silently built unlayered. Preserve layer, including the empty string.
- The manifest reader extracted the shared package/version from a fixed
  space-delimited position, which the structural identifiers
  (provide shared module [<key>]@<version> = ...) move; it also cast the
  container-entry bracket payload to an expose-pair array, which the
  layered [exposes, layers] tuple breaks with a TypeError. Decode the
  structural key by its length-prefixed components and validate both
  container payload generations (and array share-scope prefixes),
  keeping the legacy formats working.

Shared records are still aggregated by package name only; representing
concrete provider variants is coordinated separately with the native
manifest producer.
@changeset-bot

changeset-bot Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8585d13

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 48 packages
Name Type
@module-federation/managers Patch
@module-federation/runtime-core Patch
@module-federation/sdk Patch
@module-federation/webpack-bundler-runtime Patch
@module-federation/enhanced Patch
@module-federation/manifest Patch
@module-federation/dts-plugin Patch
@module-federation/rspack Patch
@module-federation/nextjs-mf Patch
@module-federation/runtime Patch
@module-federation/bridge-react Patch
@module-federation/devtools Patch
@module-federation/cli Patch
@module-federation/esbuild Patch
@module-federation/metro Patch
@module-federation/modern-js-v3 Patch
@module-federation/modern-js Patch
@module-federation/node Patch
@module-federation/observability-plugin Patch
@module-federation/retry-plugin Patch
@module-federation/rsbuild-plugin Patch
@module-federation/rspress-plugin Patch
@module-federation/rstest Patch
@module-federation/storybook-addon Patch
@module-federation/utilities Patch
@module-federation/bridge-react-webpack-plugin Patch
@module-federation/bridge-vue3 Patch
@module-federation/runtime-tools Patch
shared-tree-shaking-no-server-host Patch
shared-tree-shaking-no-server-provider Patch
@module-federation/playground Patch
website-new Patch
@module-federation/metro-plugin-rnc-cli Patch
@module-federation/metro-plugin-rnef Patch
@module-federation/metro-plugin-rock Patch
shared-tree-shaking-with-server-host Patch
shared-tree-shaking-with-server-provider Patch
node-dynamic-remote-new-version Patch
node-dynamic-remote Patch
remote5 Patch
remote6 Patch
@module-federation/inject-external-runtime-core-plugin Patch
create-module-federation Patch
@module-federation/error-codes Patch
@module-federation/third-party-dts-extractor Patch
@module-federation/treeshake-frontend Patch
@module-federation/treeshake-server Patch
@module-federation/bridge-shared Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@module-federation/devtools

pnpm add https://pkg.pr.new/@module-federation/devtools@8585d13

@module-federation/cli

pnpm add https://pkg.pr.new/@module-federation/cli@8585d13

create-module-federation

pnpm add https://pkg.pr.new/create-module-federation@8585d13

@module-federation/dts-plugin

pnpm add https://pkg.pr.new/@module-federation/dts-plugin@8585d13

@module-federation/enhanced

pnpm add https://pkg.pr.new/@module-federation/enhanced@8585d13

@module-federation/error-codes

pnpm add https://pkg.pr.new/@module-federation/error-codes@8585d13

@module-federation/esbuild

pnpm add https://pkg.pr.new/@module-federation/esbuild@8585d13

@module-federation/managers

pnpm add https://pkg.pr.new/@module-federation/managers@8585d13

@module-federation/manifest

pnpm add https://pkg.pr.new/@module-federation/manifest@8585d13

@module-federation/metro

pnpm add https://pkg.pr.new/@module-federation/metro@8585d13

@module-federation/metro-plugin-rnc-cli

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rnc-cli@8585d13

@module-federation/metro-plugin-rnef

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rnef@8585d13

@module-federation/metro-plugin-rock

pnpm add https://pkg.pr.new/@module-federation/metro-plugin-rock@8585d13

@module-federation/modern-js

pnpm add https://pkg.pr.new/@module-federation/modern-js@8585d13

@module-federation/modern-js-v3

pnpm add https://pkg.pr.new/@module-federation/modern-js-v3@8585d13

@module-federation/native-federation-tests

pnpm add https://pkg.pr.new/@module-federation/native-federation-tests@8585d13

@module-federation/native-federation-typescript

pnpm add https://pkg.pr.new/@module-federation/native-federation-typescript@8585d13

@module-federation/nextjs-mf

pnpm add https://pkg.pr.new/@module-federation/nextjs-mf@8585d13

@module-federation/node

pnpm add https://pkg.pr.new/@module-federation/node@8585d13

@module-federation/observability-plugin

pnpm add https://pkg.pr.new/@module-federation/observability-plugin@8585d13

@module-federation/playground

pnpm add https://pkg.pr.new/@module-federation/playground@8585d13

@module-federation/retry-plugin

pnpm add https://pkg.pr.new/@module-federation/retry-plugin@8585d13

@module-federation/rsbuild-plugin

pnpm add https://pkg.pr.new/@module-federation/rsbuild-plugin@8585d13

@module-federation/rspack

pnpm add https://pkg.pr.new/@module-federation/rspack@8585d13

@module-federation/rspress-plugin

pnpm add https://pkg.pr.new/@module-federation/rspress-plugin@8585d13

@module-federation/rstest

pnpm add https://pkg.pr.new/@module-federation/rstest@8585d13

@module-federation/runtime

pnpm add https://pkg.pr.new/@module-federation/runtime@8585d13

@module-federation/runtime-core

pnpm add https://pkg.pr.new/@module-federation/runtime-core@8585d13

@module-federation/runtime-tools

pnpm add https://pkg.pr.new/@module-federation/runtime-tools@8585d13

@module-federation/sdk

pnpm add https://pkg.pr.new/@module-federation/sdk@8585d13

@module-federation/storybook-addon

pnpm add https://pkg.pr.new/@module-federation/storybook-addon@8585d13

@module-federation/third-party-dts-extractor

pnpm add https://pkg.pr.new/@module-federation/third-party-dts-extractor@8585d13

@module-federation/treeshake-frontend

pnpm add https://pkg.pr.new/@module-federation/treeshake-frontend@8585d13

@module-federation/treeshake-server

pnpm add https://pkg.pr.new/@module-federation/treeshake-server@8585d13

@module-federation/typescript

pnpm add https://pkg.pr.new/@module-federation/typescript@8585d13

@module-federation/utilities

pnpm add https://pkg.pr.new/@module-federation/utilities@8585d13

@module-federation/webpack-bundler-runtime

pnpm add https://pkg.pr.new/@module-federation/webpack-bundler-runtime@8585d13

@module-federation/bridge-react

pnpm add https://pkg.pr.new/@module-federation/bridge-react@8585d13

@module-federation/bridge-react-webpack-plugin

pnpm add https://pkg.pr.new/@module-federation/bridge-react-webpack-plugin@8585d13

@module-federation/bridge-shared

pnpm add https://pkg.pr.new/@module-federation/bridge-shared@8585d13

@module-federation/bridge-vue3

pnpm add https://pkg.pr.new/@module-federation/bridge-vue3@8585d13

@module-federation/inject-external-runtime-core-plugin

pnpm add https://pkg.pr.new/@module-federation/inject-external-runtime-core-plugin@8585d13

commit: 8585d13

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Bundle Size Report

10 package(s) changed, 33 unchanged.

Package dist + ESM entry

Package Total dist (raw) Delta ESM gzip Delta
@module-federation/enhanced 820.4 kB +3.2 kB (+0.4%) 672 B no change
@module-federation/managers 71.0 kB +268 B (+0.4%) 244 B no change
@module-federation/manifest 163.6 kB +31.6 kB (+23.9%) 106 B no change
@module-federation/playground 16.07 MB -140 B (-0.0%) 45.6 kB no change
@module-federation/sdk 129.5 kB +620 B (+0.5%) 785 B no change

Bundle targets

Package Web bundle (gzip) Delta Node bundle (gzip) Delta
@module-federation/cli 2.3 kB -9 B (-0.4%) 2.4 kB -34 B (-1.4%)
@module-federation/core 1.0 kB no change 1.0 kB -35 B (-3.2%)
@module-federation/devtools 30.3 kB -6 B (-0.0%) 30.3 kB -30 B (-0.1%)
@module-federation/enhanced 2.7 kB +9 B (+0.3%) 2.8 kB -45 B (-1.6%)
@module-federation/managers 2.4 kB +30 B (+1.2%) 2.4 kB +30 B (+1.2%)
@module-federation/manifest 7.8 kB +2.2 kB (+40.0%) 7.8 kB +2.2 kB (+40.0%)
@module-federation/metro-plugin-rnc-cli 416 B -1 B (-0.2%) 435 B -27 B (-5.8%)
@module-federation/node 9.1 kB no change 9.2 kB -29 B (-0.3%)

Consumer scenarios

Scenario Web output (gzip) Delta Node output (gzip) Delta Gap (node-web) Delta
Enhanced remoteEntry 22.3 kB -15 B (-0.1%) 23.8 kB -13 B (-0.1%) +1.6 kB +2 B

Total dist (raw): 23.35 MB (+35.6 kB (+0.1%))
Total ESM gzip: 111.4 kB (no change)
Total web bundle (gzip): 255.3 kB (+2.2 kB (+0.9%))
Total node bundle (gzip): 257.5 kB (+2.1 kB (+0.8%))
Tracked ./bundler entry gzip: 563 B (no change)
Tracked ./bundler web bundle (gzip): 4.9 kB (no change)
Tracked ./bundler node bundle (gzip): 4.9 kB (no change)

Bundle sizes are generated with rslib (Rspack). Package-root metrics preserve the historical report. Tracked subpath exports such as ./bundler are measured separately so ENV_TARGET-driven tree-shaking is visible. Bare imports are externalized to keep package-level sizes consistent, and assets are emitted as resources.

…ayers

Rspack's layer-aware stack now emits the same identifier layouts as
webpack's enhanced plugin: shared modules insert a ' (layer)' segment
after the '(scope)' segment and keep 'name@version' at its legacy token
position; container entries keep the '[[key, options]]' payload with a
'layer' inside the expose options when present. Drop the structural-key
and tuple decoding that the earlier draft anticipated and parse the
layer segment instead (for webpack provide identifiers too).

Add a compatibility suite that runs the last published reader
(@module-federation/manifest@2.8.2, aliased as a dev dependency) and the
current source against the same Rspack-shaped identifiers: unlayered
shares and containers (with or without a layered expose) read
identically, layered shares are skipped by the old reader without
failing, and the superseded structural/tuple shapes are documented as
breaking it.
@ScriptedAlchemy ScriptedAlchemy changed the title fix(manifest,managers): support Rspack layered shared metadata feat(enhanced): align Webpack and Rspack layer support Sep 14, 2026
@ScriptedAlchemy
ScriptedAlchemy changed the base branch from main to codex/manifest-graph-foundation September 15, 2026 01:20
@ScriptedAlchemy

Copy link
Copy Markdown
Member Author

A pkg.pr.new preview now exists for the current top of the Rspack stack, @rspack/core@45470d0c8b90d99dba321ee810c17142ad0bfb3a (#14913 head, includes tonight's review fixes and the main 2.2.4 merge). I ran RspackCompatibility, ManifestReaderCompatibility, and RspackLayers against it locally: 25 of 25 pass once line 83 of RspackCompatibility.spec.ts expects 2.2.4 instead of 2.2.3. The old-host case (Rspack 1.3.9, runtime 0.13.1) loads the new unlayered remote through both remoteEntry.js and mf-manifest.json in default and custom scopes. When the pin is refreshed here, that version expectation needs the same bump. Nothing pushed to this branch.

@ScriptedAlchemy

Copy link
Copy Markdown
Member Author

Two docs gaps against the checklist, from a read of the diff. apps/website-new/docs/{en,zh}/configure/exposes.mdx has no layer entry yet; it should say that module-rule layer takes precedence, that omitting it keeps current behavior, and that an empty string is rejected (the schema already does, ExposeLayerSchema.test.ts). And the Rspack side of the relative-consume question is now settled to match this PR: web-infra-dev/rspack#12977 at 89533c8108 resolves unlayered relative shared requests and fallback imports against the compiler context again, and only issuerLayer consumes from the issuer, the same scoping resolveMatchedConfigs.ts uses here.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant