fix(webpack-bundler-runtime): preserve share scopes on repeated init - #4698
fix(webpack-bundler-runtime): preserve share scopes on repeated init#46982heal1 wants to merge 2 commits into
Conversation
Reuse an existing non-default share scope when repeated container init receives an incomplete host shareScopeMap instead of overwriting it with an empty scope or the wrong fallback. Add a regression test covering repeated init with empty and missing custom share-scope entries, and keep the related initContainerEntry array/non-array test suites green.
🦋 Changeset detectedLatest commit: 0760c76 The changes in this PR will be included in the next version bump. This PR includes changesets to release 45 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 |
✅ Deploy Preview for module-federation-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
@module-federation/devtools
@module-federation/cli
create-module-federation
@module-federation/dts-plugin
@module-federation/enhanced
@module-federation/error-codes
@module-federation/esbuild
@module-federation/managers
@module-federation/manifest
@module-federation/metro
@module-federation/metro-plugin-rnc-cli
@module-federation/metro-plugin-rnef
@module-federation/metro-plugin-rock
@module-federation/modern-js
@module-federation/modern-js-v3
@module-federation/native-federation-tests
@module-federation/native-federation-typescript
@module-federation/nextjs-mf
@module-federation/node
@module-federation/observability-plugin
@module-federation/retry-plugin
@module-federation/rsbuild-plugin
@module-federation/rspack
@module-federation/rspress-plugin
@module-federation/runtime
@module-federation/runtime-core
@module-federation/runtime-tools
@module-federation/sdk
@module-federation/storybook-addon
@module-federation/third-party-dts-extractor
@module-federation/treeshake-frontend
@module-federation/treeshake-server
@module-federation/typescript
@module-federation/utilities
@module-federation/webpack-bundler-runtime
@module-federation/bridge-react
@module-federation/bridge-react-webpack-plugin
@module-federation/bridge-shared
@module-federation/bridge-vue3
@module-federation/inject-external-runtime-core-plugin
commit: |
Bundle Size Report30 package(s) changed, 11 unchanged. Package dist + ESM entry
Bundle targets
Tree-shakable entrypoints
Consumer scenarios
Total dist (raw): 6.80 MB (+617.9 kB (+9.7%)) Bundle sizes are generated with rslib (Rspack). Package-root metrics preserve the historical report. Tracked subpath exports such as |
| }; | ||
|
|
||
| // host: 'default' remote: 'default' remote['default'] = hostShareScopeMap['default'] | ||
| // host: ['default', 'scope1'] remote: 'default' remote['default'] = hostShareScopeMap['default']; remote['scope1'] = hostShareScopeMap['scop1'] |
There was a problem hiding this comment.
Typo: hostShareScopeMap['scop1'] → scope1
| expect(mockIFunction).toHaveBeenCalledTimes(3); | ||
| }); | ||
|
|
||
| test('should preserve non-default share scopes across repeated init with incomplete host shareScopeMap', () => { |
There was a problem hiding this comment.
These assertions cover persistence of custom, but the visible symptom in #4691 was a cross-scope leak — entries showing up under both default and custom. Could you add an isolation assertion here, e.g. expect(federationInstance.shareScopeMap.default).not.toHaveProperty('') (or assert default's keys are unchanged after this re-init)? That locks in the actual user-facing bug, not just that custom survives.
| const resolveShareScope = ( | ||
| key: string, | ||
| fallbackShareScope: Record<string, any>, | ||
| options: { fallbackWhenEmpty?: boolean } = {}, | ||
| ) => { | ||
| const currentShareScope = hostShareScopeMap[key]; | ||
|
|
||
| if ( | ||
| hasOwnScope(hostShareScopeMap, key) && | ||
| !isEmptyShareScope(currentShareScope) | ||
| ) { | ||
| return currentShareScope; | ||
| } | ||
|
|
||
| if ( | ||
| hasOwnScope(existingShareScopeMap, key) && | ||
| (!hasOwnScope(hostShareScopeMap, key) || | ||
| isEmptyShareScope(currentShareScope)) | ||
| ) { | ||
| return existingShareScopeMap[key]; | ||
| } | ||
|
|
||
| if (hasOwnScope(hostShareScopeMap, key)) { | ||
| return options.fallbackWhenEmpty && isEmptyShareScope(currentShareScope) | ||
| ? fallbackShareScope | ||
| : currentShareScope; | ||
| } | ||
|
|
||
| return fallbackShareScope; | ||
| }; |
There was a problem hiding this comment.
Consider a short JSDoc summarizing the precedence: non-empty host scope wins → fall back to existing populated scope → fallback. The logic is subtle enough that the next maintainer will appreciate it.
| const sc = resolveShareScope(hostKey, {}); | ||
| if ( | ||
| !hasOwnScope(hostShareScopeMap, hostKey) || | ||
| (hasOwnScope(existingShareScopeMap, hostKey) && | ||
| isEmptyShareScope(hostShareScopeMap[hostKey])) | ||
| ) { | ||
| hostShareScopeMap[hostKey] = sc; |
There was a problem hiding this comment.
Minor/readability: the string-key branch writes the resolved scope back into hostShareScopeMap[hostKey], but the array-shareScopeKey branch doesn't. Not a correctness issue (the array path works without it), but the asymmetry is confusing — a one-line comment on why the write-back is only needed in one branch would help.
|
Up |
Reuse an existing non-default share scope when repeated container init receives an incomplete host shareScopeMap instead of overwriting it with an empty scope or the wrong fallback.
Add a regression test covering repeated init with empty and missing custom share-scope entries, and keep the related initContainerEntry array/non-array test suites green.
Description
Related Issue
#4691
Types of changes
Checklist