Skip to content

fix(runtime-core): select highest compatible shared version - #4962

Open
dmchoi77 wants to merge 3 commits into
module-federation:mainfrom
dmchoi77:fix/analyze-shared-version-selection
Open

fix(runtime-core): select highest compatible shared version#4962
dmchoi77 wants to merge 3 commits into
module-federation:mainfrom
dmchoi77:fix/analyze-shared-version-selection

Conversation

@dmchoi77

@dmchoi77 dmchoi77 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Fix non-singleton shared-version fallback when the overall highest registered version does not satisfy requiredVersion.

The resolver now filters candidates by requiredVersion before selecting the highest semver version. The tree-shaking fallback applies the same rule after filtering for eligible tree-shaking candidates, making the selected version independent of share registration order.

Adds regression coverage for two registration orders with and without tree shaking, and includes a patch changeset for @module-federation/runtime-core.

Related Issue

Closes #4961

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

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

@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4cf7e3a

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/runtime-core Patch
@module-federation/nextjs-mf Patch
@module-federation/runtime Patch
@module-federation/bridge-react Patch
@module-federation/devtools Patch
@module-federation/dts-plugin 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/playground Patch
@module-federation/retry-plugin Patch
@module-federation/runtime-tools Patch
@module-federation/webpack-bundler-runtime Patch
@module-federation/bridge-vue3 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
@module-federation/rsbuild-plugin Patch
@module-federation/rstest Patch
node-dynamic-remote-new-version Patch
node-dynamic-remote Patch
@module-federation/enhanced Patch
@module-federation/rspack Patch
@module-federation/inject-external-runtime-core-plugin Patch
@module-federation/rspress-plugin Patch
remote5 Patch
remote6 Patch
@module-federation/storybook-addon Patch
shared-tree-shaking-no-server-host Patch
shared-tree-shaking-no-server-provider Patch
@module-federation/sdk Patch
@module-federation/managers Patch
@module-federation/manifest Patch
@module-federation/third-party-dts-extractor Patch
@module-federation/bridge-shared Patch
@module-federation/bridge-react-webpack-plugin Patch
@module-federation/error-codes Patch
create-module-federation Patch
@module-federation/cli Patch
@module-federation/treeshake-server Patch
@module-federation/treeshake-frontend Patch
@module-federation/utilities 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

@2heal1

2heal1 commented Aug 18, 2026

Copy link
Copy Markdown
Member

Thanks for the reproduction. However, it directly constructs the internal ShareScopeMap and assumes that the highest compatible version is the required outcome.
This PR changes observable non-singleton fallback behavior from “first compatible version in registration order” to “highest compatible version.” It may therefore affect applications that currently rely on registration order, and the change also appears to affect loaded-first.
Could you provide an integration-level reproduction using actual host and remote configurations?
In particular, please demonstrate:

  1. How 1.0.0, 1.9.0, and 2.0.0 are naturally registered into the same share scope.
  2. Which application consumes the share with requiredVersion: ^1.0.0.
  3. The concrete user-visible failure caused by selecting 1.0.0, despite it satisfying the declared range.
  4. Why the requirement cannot instead be expressed as >=1.9.0 if 1.9.0 is actually required.
  5. Whether the proposed highest-compatible behavior is intended only for version-first, and what should happen under loaded-first.

Without such a scenario, the current reproduction establishes an order-dependent implementation detail, but does not yet establish that changing the existing selection policy is safe or necessary.

@dmchoi77

Copy link
Copy Markdown
Contributor Author

@2heal1 Thanks for the detailed feedback. I agree that the original reproduction only exercised the internal ShareScopeMap. I added integration-level coverage to this PR and updated the public reproduction:

  • The integration test uses an actual ModuleFederation host with shareStrategy: 'version-first'.
  • Through the normal remote-entry initialization path, three remote entries register 1.0.0, 1.9.0, and 2.0.0 into the same share scope.
  • The host consumes shared-version-selection with requiredVersion: '^1.0.0' and singleton: false.
  • Each shared implementation exposes a different render() result, making the selected version observable at the consumer boundary.
  • With @module-federation/runtime-core@2.8.1, the host selects 1.0.0 for the registration order 1.0.0 -> 1.9.0 -> 2.0.0.
  • With this PR's version-first implementation, the same host/remote setup selects 1.9.0.

I verified the public reproduction by running pnpm test. With @module-federation/runtime-core@2.8.1, 4 of 6 tests fail: both the direct and host/remote integration cases select 1.0.0 instead of 1.9.0. The registration-order and loaded-first control tests pass.

The public reproduction is intentionally pinned to @module-federation/runtime-core@2.8.1 and does not include the fix from this PR:

Public reproduction

The ^1.0.0 range is intentional: the fixture models a consumer that accepts the full 1.x compatibility range while expecting version-first negotiation to prefer the newest compatible implementation. If 1.9.0 is a hard minimum rather than a preference, >=1.9.0 would be the more precise requirement.

The proposed behavior is scoped to version-first. A shared entry using loaded-first keeps its existing loaded/loading priority and registration-order fallback, with separate regression coverage for both normal and tree-shaking paths.

Could you confirm whether this matches the intended negotiation policy? If version-first is also expected to preserve first-compatible fallback behavior, I can revise the implementation accordingly.

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.

runtime-core selects the first compatible shared version instead of the highest one

2 participants