feat(runtime): support auth headers and additional fetch options when loading remote modules#4827
feat(runtime): support auth headers and additional fetch options when loading remote modules#4827smeng9 wants to merge 30 commits into
Conversation
Design for threading per-remote fetchOptions through registerRemotes so auth/compliance headers reach every asset in the ESM module graph (manifest, entry, chunks, shared deps, manifest CSS) via a fetch + blob import-rewriting loader. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…motes Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… loading Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Distinguishes the JS module blob cache from cssCache. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dom.iterable surfaces Headers.entries()/Symbol.iterator on the standard DOM types, so toHeaderObject can use Object.fromEntries(headers.entries()) without the unknown-cast workaround. Verified: all 42 packages build, sdk type-checks, sdk tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Call-level fetchOptions now act as defaults that each remote's own fetchOptions are merged on top of (remote wins on conflict), with headers merged per-key so a remote adding one header no longer drops the call-level ones. Exposes toHeaderObject from sdk to share the header-normalization used by the merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The entry preload in preloadAssets used the snapshot-derived moduleInfo, which does not carry the host remote's fetchOptions. The remoteEntry was therefore preloaded unauthenticated and cached, so the later authenticated load was skipped and no Authorization header reached the remoteEntry or its chunks. Forward remoteInfo.fetchOptions to the entry preload (mirroring the css path). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: f9438b0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 46 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. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e3686009e9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…docs Document the per-remote/call-level fetchOptions option on registerRemotes in the runtime API reference (en + zh), and remove the internal superpowers plan/spec scratch files under docs/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- runtime-core/load: wrap blob-loader ESM entry failures as RUNTIME_008 so getRemoteEntry's loadEntryError recovery (token refresh, failover) still fires for authenticated ESM remotes - runtime-core/preload: skip applying authenticated CSS during preload hints (useLinkPreload) so a remote's stylesheet no longer overrides host styles before the remote is loaded - sdk/blobLoad: store dynamic-import contexts in a shared globalThis registry and stop clobbering an existing __mfDyn shim, so blob modules keep their fetch context when two bundled copies of the SDK coexist Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Instead of adding a separate __MF_BLOB_LOAD_CONTEXTS__ global, attach the shared dynamic-import context map as a property of the single global __mfDyn shim. Avoids polluting globalThis with a second variable while keeping the cross-SDK-copy guarantee: every copy reads/writes the same map through whichever shim is installed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getContexts() already installs the __mfDyn shim idempotently, so the only thing the flag still guarded was duplicate vite:preloadError listeners. Use a stable handler reference instead — addEventListener treats an identical (callback, capture) pair as a no-op — and remove the flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4a5e692 to
2f1fb20
Compare
- __mfDyn -> __mfDynImport (global dynamic-import shim) - MFDynShim -> MFDynImportShim - getContexts -> createOrGetBlobLoaderContexts - shim.contexts -> shim.blobLoaderContexts - BlobLoadContext -> BlobLoaderContext Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2f1fb20 to
1adcded
Compare
Extract pushCssAsset so the three CSS branches (authenticated fetch, rel=preload hint, applied rel=stylesheet) share a single forEach instead of repeating the cssAssets.forEach/results.push boilerplate. Behavior is unchanged: needDeleteLink stays undefined for the preload hint and false for the applied stylesheet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
00527f7 to
9195060
Compare
|
The ESM loading direction makes sense, but I don't think The runtime already has a This also avoids expanding the public remote config API. Users can already decide headers based on So I think the change should keep remote registration unchanged, and make ESM remote entry / related ESM asset loading go through the existing |
…registerRemotes config
Address PR review (2heal1): header/auth customization is request behavior, so
configure it through the existing `fetch` hook (which already receives
`remoteInfo`) rather than a new `fetchOptions` field on remote registration.
- Remove `fetchOptions` from `RemoteInfoCommon`/`RemoteInfo`, the
`registerRemotes` options, and the call-level merge helper; revert the
manifest fetch to its prior `{}` init (it already passed `remoteInfo`).
- Gate the ESM remote-entry and manifest-CSS blob loaders on fetch-hook
presence (`loaderHook.fetch.listeners.size > 0`) instead of `fetchOptions`,
routing their requests through the hook with `remoteInfo`/`resourceContext`.
With no fetch hook, remotes load via native import()/<link> as before.
- Rename/rewrite tests to cover the hook-presence gate; update EN/ZH docs to
document the `fetch` hook approach and refresh the changeset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng behavior The test only asserted that the manifest request is emitted through the fetch hook with remoteInfo as the 3rd arg — behavior that predates this branch (it was already in place at v2.5.0) and that the test never inspected the init arg this branch actually touched. It guarded no code introduced here, so remove it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Hi @2heal1 I have applied your suggestions to keep the function signature the same for registerRemotes. Would you mind take another look? Thanks! |
Description
A compliance requirement in the backend gateway needs an Authorization: Bearer … header (plus arbitrary X-* headers) for loading remote modules. Previously all assets that are fetched with no authorization header will be rejected under new access control model.
This PR adds per-remote fetchOptions so federated ESM/module remotes can be loaded with custom HTTP headers on their manifest, remote entry, split chunks, shared deps, and CSS requests.
Related Issue
Multiple people had requested this feature before
module-federation/utilities#13
module-federation/enhanced#21
Additionally previous discussions are outdated,
they involve webpack require() instead of esm import()
#1115
Types of changes
Checklist