Skip to content

Conversation

@gocamille
Copy link

@gocamille gocamille commented Jan 27, 2026

Summary

This PR enables apollo-client-devtools to detect and interact with Apollo Clients running inside same-origin iframes, in addition to the main window.

Problem

Previously we only detected clients in the top-level window. If a page had iframes with their own Apollo Client instances, those clients were invisible to the extension.

Solution

  1. Updated extension manifests: Added all_frames: true to content scripts so tab.js and hook.js run in every frame (main window + iframes)
  2. Added multi-port architecture with frameId tracking: Changed background.ts from tracking a single tab port per tab to a Map<tabPorts, frameId> per tab, enabling multiple frames to connect while tracking which frame each port belongs to
  3. Introduced client --> frame mapping: Added a clientFrames: Map<clientId, frameId> to track which Apollo Client belongs to which frame, enabling targeted message routing
  4. Implemented frameId-based message routing: RPC requests for a specific client are now routed only to the frame that owns that client, eliminating broadcast overhead
  5. Added SKIP_RESPONSE pattern for discovery: The getClients handler in hook.ts uses SKIP_RESPONSE so frames without Apollo Clients don't pollute discovery responses

Files Changed

File Change
src/extension/chrome/manifest.json Add all_frames: true
src/extension/firefox/manifest.json Add all_frames: true
src/extension/rpc.ts Export SKIP_RESPONSE symbol + handler logic to skip sending responses
src/extension/background/background.ts Set<tabPorts> --> Map<Port, frameId>, add clientFrames mapping, implement targeted routing
src/extension/tab/hook.ts Add SKIP_RESPONSE to getClients handler for frames without clients
src/extension/tab/handleExplorerRequests.ts Replace throw with silent return
development/client/public/iframe.html Test page for iframe scenarios

Automated Tests Added

Two new unit tests in src/extension/__tests__/rpc.test.ts:

Test Description
does not send response when handler returns SKIP_RESPONSE Verifies that when a handler returns SKIP_RESPONSE, no RPC response message is posted
SKIP_RESPONSE allows handler to be re-registered after unsubscribe Verifies that handlers using SKIP_RESPONSE can be properly unsubscribed and re-registered

Manual Verification Steps

  1. Single frame (regression test)

    • Load a page with a single Apollo Client (no iframes)
    • Open DevTools --> Apollo tab
    • Verify the client is detected and all features (Queries, Mutations, Cache) work normally
  2. Multi-frame detection

    • Start dev server: npm run start:dev
    • Open Chrome with the extension loaded: npm run chrome
    • Navigate to http://localhost:3000
    • Add a client in the main window and a client inside the iframe
    • Verify both clients appear in the DevTools client dropdown
  3. Targeted routing verification

    • With both clients (main window + iframe) registered from step 2
    • Select the iframe's client in DevTools
    • Run queries/mutations and inspect the cache
    • In Chrome DevTools console for the background script, confirm RPC requests are routed only to the correct frame (look for frameId in console logs in dev mode)

Limitations

  • Same-origin only: Per browser security, all_frames: true only works for same-origin iframes. Cross-origin iframes remain invisible.

References

@relativeci
Copy link

relativeci bot commented Jan 27, 2026

#1764 Bundle Size — 2.01MiB (+0.07%).

26712e0(current) vs 8961f38 main#1758(baseline)

Warning

Bundle contains 14 duplicate packages – View duplicate packages

Bundle metrics  Change 3 changes Regression 1 regression
                 Current
#1764
     Baseline
#1758
Regression  Initial JS 1.73MiB(+0.07%) 1.73MiB
No change  Initial CSS 0B 0B
Change  Cache Invalidation 85.12% 0%
No change  Chunks 5 5
No change  Assets 235 235
No change  Modules 1527 1527
No change  Duplicate Modules 134 134
Change  Duplicate Code 5.72%(+0.18%) 5.71%
No change  Packages 179 179
No change  Duplicate Packages 11 11
Bundle size by type  Change 2 changes Regression 2 regressions
                 Current
#1764
     Baseline
#1758
Regression  JS 1.73MiB (+0.07%) 1.73MiB
Regression  Other 251.35KiB (+0.05%) 251.23KiB
No change  IMG 35.85KiB 35.85KiB
No change  HTML 857B 857B

Bundle analysis reportBranch feat/iframe-supportProject dashboard


Generated by RelativeCIDocumentationReport issue

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 27, 2026

npm i https://pkg.pr.new/apollographql/apollo-client-devtools@1797
npm i https://pkg.pr.new/apollographql/apollo-client-devtools/@apollo/client-devtools-vscode@1797

commit: 26712e0

port.onDisconnect.addListener(() => {
ports[tabId].disconnectPorts?.();
ports[tabId].tab = null;
ports[tabId].tabPorts.delete(port);
Copy link
Member

Choose a reason for hiding this comment

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

Note to self to dive in a bit deeper tomorrow:

I wonder if there is a chance to use the frameId as part of this identifier instead of using a Set. The idea is that if we can beef up the id a bit more, hopefully that would simplify some of the handling in other places where we don't have to try and ignore some messages due to it broadcasting to all frames on the same tab ID.

@gocamille gocamille force-pushed the feat/iframe-support branch from aff9c7d to 26712e0 Compare January 28, 2026 22:22
@gocamille gocamille marked this pull request as ready for review January 28, 2026 22:34
@gocamille gocamille requested a review from a team as a code owner January 28, 2026 22:34
@gocamille gocamille requested a review from jerelmiller January 28, 2026 22:34
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.

3 participants