Repository navigation
fix(managers,rspack,enhanced): resolve canonical share keys for relative imports (#5042) - #5065
Conversation
🦋 Changeset detectedLatest commit: 5b7bfe8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 48 packages
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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3cb846129c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } else if (item && typeof item === 'object') { | ||
| for (const k of Object.keys(item)) { | ||
| keys.add(k); | ||
| } |
There was a problem hiding this comment.
Honor request overrides when canonicalizing shared imports
When a valid shared entry uses request to match a canonical import under a different configuration key (for example, { internal: { request: '@scope/pkg/context', import: '@scope/pkg/context' } }), this extracts only internal. ConsumeSharedPlugin matches that configuration using config.request, but the canonical candidate @scope/pkg/context is absent from this set, so relative imports are never rewritten and still create the duplicate local instance this feature is intended to avoid. Include configured request values in the canonical match set.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 5b7bfe8. extractSharedKeys now extracts configured request overrides (e.g. { internal: { request: '@scope/pkg/context' } }) so canonical candidates match the configured share entry.
| for (const c of candidates) { | ||
| if (sharedKeys.has(c)) { | ||
| return c; |
There was a problem hiding this comment.
Match trailing-slash shared prefixes
For supported prefix sharing such as shared: { '@scope/pkg/': { singleton: true } }, a relative import resolving to @scope/pkg/context produces that full candidate, but this exact membership test cannot match the configured prefix. The sharing implementation treats trailing-slash requests as prefix matches, so the canonicalization layer leaves these internal relative imports local and the singleton-duplication issue persists for prefix-based shared configurations.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 5b7bfe8. Added prefixes array in SharedKeysSet to track trailing-slash prefixes and perform prefix matching via isMatch / isSharedKeyMatch, allowing relative imports to match prefix shared rules like @scope/pkg/.
…tive imports (module-federation#5042) In monorepos or multi-package repositories where packages use relative imports internally (e.g. `import { Context } from './FeatureTypeContext'`) while external consumers import via canonical package specifier (e.g. `import { Context } from '@pkg/context-lib/FeatureTypeContext'`), Module Federation previously bundled duplicate local instances because sharing was negotiated strictly by the raw import request string. This adds CanonicalSharedPlugin in @module-federation/managers, which is applied by @module-federation/rspack and @module-federation/enhanced: 1. Intercepts relative requests in normalModuleFactory.hooks.beforeResolve. 2. Locates the nearest package.json for the resolved target path. 3. Matches root packages, exports field, relative subpaths, and trailing-slash prefixes against configured shared keys. 4. Honors configured request overrides (e.g. { alias: { request: 'pkg' } }). 5. Rewrites matching relative requests to canonical shared package specifiers before factorization so intra-package imports negotiate the shared singleton instance.
3cb8461 to
5b7bfe8
Compare
Description
Problem
In monorepos or multi-package repositories where packages use relative imports internally (e.g.
import { Context } from './FeatureTypeContext') while external consumers import via the canonical package specifier (e.g.import { Context } from '@pkg/context-lib/FeatureTypeContext'), Module Federation previously bundled duplicate local instances because sharing was negotiated strictly by the raw import request specifier.The existing
allowNodeModulesSuffixMatchoption (extractPathAfterNodeModules) only checks for the substringnode_modulesin the file path. In modern monorepos (pnpm workspaces, npm workspaces, Lerna), workspace packages live under repository subdirectories (such aspackages/*) and do not containnode_modules/in their path, leaving relative imports unshared and splitting singleton contexts across host and remote compilations.Solution
This introduces
CanonicalSharedPluginin@module-federation/managers, which is applied automatically by@module-federation/rspackand@module-federation/enhancedwhensharedoptions are configured:normalModuleFactory.hooks.beforeResolve.package.jsonfor the resolved target path (with memoizedpkgCachefor build performance).package.jsonexportsentries, and relative subpaths against configuredsharedKeys.Result
Relative imports within a shared package/subpath now cleanly delegate to the federated shared scope (
webpack/sharing/consume/...) instead of embedding private local duplicates in chunks, resolving singleton fragmentation across host and remote builds.Related Issue
Fixes #5042
Related: module-federation/vite#329, #4283
Types of changes
Checklist