Skip to content

fix: seed subpath shares before their package root#892

Open
YurySolovyov wants to merge 3 commits into
module-federation:mainfrom
YurySolovyov:fix/seed-subpath-shares-before-package-root
Open

fix: seed subpath shares before their package root#892
YurySolovyov wants to merge 3 commits into
module-federation:mainfrom
YurySolovyov:fix/seed-subpath-shares-before-package-root

Conversation

@YurySolovyov

Copy link
Copy Markdown

Problem

Regression in 1.16.14 (works in 1.16.13), dev serve only. When a symlinked (file:/workspace) package is shared as a singleton together with one of its exact-key subpath exports, and the package's own source imports that subpath through a self-referencing bare specifier:

// packages/widgets/index.js
import { builder } from 'widgets/api';

export const root = builder.post({ path: '/search' }); // ← TypeError
// vite.config.js
shared: {
  widgets: { singleton: true },
  'widgets/api': { singleton: true },
}

the subpath share resolves with undefined named exports at module-evaluation time:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'post')

Sharing only the subpath (without the root) works; vite build is unaffected. This is the dev-serve reincarnation of the failure family previously fixed for production builds in #767 (fixed by #774) and #805 (fixed by #807).

Root Cause

Two changes from #883 combine:

  1. Serve-mode share proxies no longer bind an eager local fallback — on a cache miss they defer export assignment into pendingShareLoads until after federation init. Correct for cache reuse, but it makes seeding order load-bearing: any share proxy hit during seeding must already be cached.
  2. The new runtime seed loop (generateRuntimeSharedCacheSeedCode) iterates Object.entries(usedShared), whose key order is alphabetical (getUsedShares().sort()). "widgets" sorts before "widgets/api", so seeding the package root await share.get() evaluates widgets/index.js while widgets/api is still unseeded — its proxy defers, its named exports stay undefined, and the root's top-level code crashes.

The dependency-first ordering from #807 (orderSharedDependenciesFirst) already exists but wasn't used by the new seed loop, and it didn't know that a package root implicitly depends on its own subpath shares.

Fix

  • orderSharedDependenciesFirst now treats a package's subpath share keys as dependencies of the package root: when visiting a root key, its subpath keys are visited (and therefore ordered) first. Subpath keys also resolve their dependency list through the root package's package.json when the subpath itself doesn't resolve to one.
  • generateRuntimeSharedCacheSeedCode seeds in getOrderedUsedShares() order (embedded at codegen time) instead of usedShared insertion order, with a runtime fallback that appends any share keys discovered after codegen so nothing is skipped.

This preserves #883's cache-reuse semantics — no eager fallback is reintroduced; the fix only makes the seeding order match the evaluation-order requirements the deferred fallback created. For the example above the seed order becomes ['widgets/api', 'widgets'], so by the time widgets/index.js evaluates, the widgets/api proxy hits a warm cache and applies its exports synchronously.

Known limitation: a genuine evaluation-time cycle (root imports subpath and subpath imports root) cannot be solved by ordering alone; that case was equally broken before this change.

Since the runtime shared cache seeding (module-federation#883), serve-mode share proxies no
longer bind an eager local fallback: on a cache miss they defer export
assignment until after federation init. The seed loop iterated usedShared in
insertion (alphabetical) order, so seeding a package root evaluated its module
graph while the package's own subpath shares were still unseeded — a
self-referencing bare import like `import { builder } from 'pkg/api'` inside
`pkg` then read undefined named exports at module-evaluation time and crashed
consumers (same failure family as module-federation#767 and module-federation#805, now in dev serve).

Seed shares in dependency order instead, treating a package's subpath share
keys as dependencies of the package root, with a runtime fallback for share
keys discovered after codegen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Jul 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@module-federation/vite@892

commit: ddb11aa

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests With Different Frameworks

Image

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants