refactor(runtime-core,sdk,runtime): split the kernel from its capabilities - #5135
ScriptedAlchemy wants to merge 14 commits into
Conversation
🦋 Changeset detectedLatest commit: b5733f4 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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8fc7ade879
ℹ️ 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".
| const instance = | ||
| current && isMatchingInstance(current, name, version) | ||
| ? current | ||
| : getGlobalFederationInstance(name, version); |
There was a problem hiding this comment.
Ignore cached current after a global reset
When resetFederationGlobalInfo() clears __INSTANCES__ and the caller subsequently initializes the same name/version, this branch reuses the stale module-local current instance instead of creating and registering a fresh one. The returned instance is therefore absent from CurrentGlobal.__FEDERATION__.__INSTANCES__, retains state from before the reset, and cannot be found through getInstance(finder); this also leaks state between existing runtime tests that reset globals after each case. Only reuse current if it is still registered globally, or clear it as part of the reset path.
AGENTS.md reference: AGENTS.md:L289-L289
Useful? React with 👍 / 👎.
Plugin hooks, globals, and helpers keep typing instances as ModuleFederation so module augmentation (bridge-react) still applies. Adds kernel and compose red-green tests.
@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/playground
@module-federation/retry-plugin
@module-federation/rsbuild-plugin
@module-federation/rspack
@module-federation/rspress-plugin
@module-federation/rstest
@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 Report15 package(s) changed, 28 unchanged. Package dist + ESM entry
Bundle targets
Tree-shakable entrypoints
Consumer scenarios
Total dist (raw): 23.34 MB (-66332 B (-0.3%)) Bundle sizes are generated with rslib (Rspack). Package-root metrics preserve the historical report. Tracked subpath exports such as |
The root ModuleFederation and FederationKernel now share a FederationCore base that takes resolved capabilities. The kernel fills missing capabilities with disabled handlers; the root picks enabled or disabled capabilities from the defines, so bundlers fold the unused side away. With remote and shared both disabled the root composes no platform, since nothing loads entries.
RemoteHandler only needs getGlobalShareScope, which lived in utils/share and pulled share and semver into builds without the shared capability. It moves to global.ts; utils/share re-exports it for existing callers.
ModuleFederation types its handlers as the RemoteHandler, SharedHandler, and SnapshotHandler classes again, as on main. Only FederationKernel narrows them to the handler contracts, and the contracts shrink to what the disabled handlers implement on main. A type test compiles a fixture that reaches manifestLoading, registerRemote, and initTokens through the root class.
rspack's native plugin bundles the CommonJS builds without tree shaking, so every module the root touches ships. CommonJS consumers of sdk ./core and runtime-core ./kernel now load the package root, which rspack already bundles. The shared, remote, and snapshot capabilities live next to their handlers, the kernel class and the unavailable platform live in core, and runtime's instance lookup joins instance.ts.
getResourceUrl took the browser decision from the environment, while the snapshot and preload plugins next to it already asked the platform. It now takes an optional isBrowser argument, defaulting to isBrowserEnv(), and runtime-core passes origin.platform.isBrowser(). A server platform in a browser-like environment no longer joins its SSR entry to the browser public path.
getRemoteEntry emits remoteHandler.hooks.lifecycle.loadEntry for every entry, including shared tree-shaking fallbacks that load without remotes. The disabled remote handler had no hooks, so those loads threw "Cannot read properties of undefined". Same fix as #5143 on main.
The composed bootstrap passes the build id as options.id, but the shared handler registers the global share scope in the constructor, before options are merged. Take the default id from the user options so the scope is keyed by the build id, as the build-id define did. (cherry picked from commit 8bdf981)
ed81dcb to
7582cb4
Compare
… capabilities Each instance records runtimeCapabilities in the format main uses (#5145): remote, shared, snapshot, and the platform target. Public init and runtime/compose init skip page-global instances whose string differs from the caller's, and public createInstance constructs its own ModuleFederation class instead of __DEBUG_CONSTRUCTOR__.
…re-kernel # Conflicts: # packages/runtime-core/src/remote/index.ts
…age root" This reverts commit 4a55565.
… runtime capabilities" This reverts commit f343cfc.
Part of RFC #5128 (alternate proposal to #5036).
Stack: 1 of 7. Base:
main. Next: #5137.Landing order: #5135 → #5137 → #5139 → #5134 → #5140 → #5141 → #5142.
Companions on main: #5143 (disabled remote loadEntry), #5144 (enhanced duplicate serializer keys). #5126 (@rspack/core 2) is on main. PR 6 and 7 include it.
What changes
Importers of the
@module-federation/runtime-core,@module-federation/runtime, and@module-federation/sdkroots see no change. Each package gains subpath entry points that let a build include only the runtime capabilities it uses. Later PRs in the stack use them to leave unused capabilities out of the module graph.runtime-core/kernelexportsFederationKernel. It takes the capabilities the caller passes (shared,remote,snapshot,platform) and builds disabled handlers for the rest. A missing platform rejects loads.runtime/composeexportsinitandcreateInstancethat take capabilities.sdk/coreandsdk/nodesplit the sdk, so web builds no longer reach the Node loader through the sdk root.ModuleFederationstill composes the full set from the existingFEDERATION_OPTIMIZE_*defines and keeps its full handler types.This PR only adds entry points. No bundler uses them until #5137 and #5140.
This PR also carries two runtime-core fixes. The disabled remote handler keeps the
loadEntryhook, because shared tree-shaking fallback entries load throughgetRemoteEntryeven when remotes are disabled. This is the same fix as #5143 on main. The shared handler registers the share scope underoptions.idwhen one is given, so a composed build keys its scope by the build id, as the build-id define did.Verification
Cannot read properties of undefinedbefore theloadEntryfix and loads after it. Two tests inkernel.spec.tscover it.FederationKernelbuilt withid: 'kernel-share-id:1.0.0'registers its share scope under that id and not under the bare name. The test fails before the fix and passes after it.beforeInitplugin that injects remotes without a remote capability, and root composition from the defines. Compose tests cover bundle-local instance reuse ahead of the page-global lookup, and a set debug constructor is ignored. A type test reachesmanifestLoading,registerRemote, andinitTokensthrough the root class. The runtime-core, runtime, and sdk suites pass.sdk/node,platform/node, or root barrel modules in its chunks.7582cb458. The full review ran at5177ef2b8. It proved the fixes, kept webpack within 1%, accepted the rspack size, confirmed that ESM builds without./kernelnever load it, and found the exports compatible. The fix(runtime-core): keep loadEntry hook when remotes are disabled #5143 port and the share-scope fix each passed a red/green delta review after it.b5733f471adds a merge ofmainat412f62e74. Its added and removed lines againstmainmatch the verified head exactly.b5733f471with 24 checks. e2e-treeshake was skipped because the affected-suite selector did not pick it.Deviations from the RFC
FederationKernelshare aFederationCorebase instead of the root extending the kernel. Running the kernel constructor would keep every disabled handler in builds that enable everything. The RFC now shows the shared base.experiments.composedRuntime, or at the major. Webpack stays within 1%.@module-federation/sdk/coreand@module-federation/runtime-core/kernelresolve to the package root. CommonJS bundles cannot drop unused modules, so a second module graph only adds bytes.getResourceUrlin the sdk takes an optionalisBrowserargument, so runtime-core asks the platform.Overlaps with open PRs
This PR carries the #5143
loadEntryfix inruntime-core/src/remote/disabled.ts. It carries no code from other open PRs. The PRs below change files this PR also changes. This PR does not include their changes.loadEntryfix on main.runtime/src/utils.ts, which this PR moves toruntime/src/instance.ts. This PR does not include that change.runtime-core/package.json,runtime/package.json,sdk/package.json, andsdk/tsdown.config.ts.runtime-core/src/core.tsandremote/index.ts.runtime-core/src/core.ts,index.ts,module/index.ts,remote/index.ts,type/config.ts, andruntime/src/index.ts.runtime-core/src/module/index.tsandshared/index.ts.runtime-core/src/shared/index.tsand__tests__/shared-diagnostics.spec.ts.runtime-core/src/remote/index.ts,shared/disabled.ts, andshared/index.ts.runtime-core/src/plugins/snapshot/index.ts,remote/index.ts, andtype/config.ts.runtime-core/src/plugins/snapshot/SnapshotHandler.ts,type/config.ts,utils/load.ts,utils/preload.ts, and__tests__/load.spec.ts.type/config.tsandutils/share.ts. fix(runtime-core): resolve remote runtime instance identity explicitly during removal #5029 changesremote/index.ts. fix(runtime): keep top-level singleton on first init #5028 changesruntime/src/index.ts. fix(webpack-bundler-runtime): preserve share scopes on repeated container init #4969 changesshared/disabled.tsandshared/index.ts. fix(runtime): enable SSR remote-entry retry and URL failover #4968 changesutils/load.ts. fix(runtime-core): select highest compatible shared version #4962 changesutils/share.ts. fix(runtime-core): sync shared options after dynamic registration #4950 changesshared/index.tsandutils/share.ts. fix(runtime): propagate share scopes to nested remotes #4913 changesshared/index.ts. feat(runtime): support auth headers and additional fetch options when loading remote modules #4827 changesutils/load.tsandutils/preload.ts.