Skip to content

Add support for inspecting iframes#997

Open
karthikiyengar wants to merge 11 commits into
apollographql:mainfrom
karthikiyengar:main
Open

Add support for inspecting iframes#997
karthikiyengar wants to merge 11 commits into
apollographql:mainfrom
karthikiyengar:main

Conversation

@karthikiyengar

@karthikiyengar karthikiyengar commented Mar 10, 2023

Copy link
Copy Markdown

Prior discussions:
#951
#380

This PR adds support for using Apollo DevTools with iframes by leveraging the all_frames capability afforded to browser extensions.

Since we're using fork actively as an internally published extension, this branch also contains some changes that upgrades the extension from Manifest V2 to V3.

jerelmiller added a commit that referenced this pull request Jun 29, 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](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/chrome/manifest.json:0:0-0:0)
| Add `all_frames: true` |
|
[src/extension/firefox/manifest.json](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/firefox/manifest.json:0:0-0:0)
| Add `all_frames: true` |
|
[src/extension/rpc.ts](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/rpc.ts:0:0-0:0)
| Export `SKIP_RESPONSE` symbol + handler logic to skip sending
responses |
|
[src/extension/background/background.ts](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/background/background.ts:0:0-0:0)
| `Set<tabPorts>` --> `Map<Port, frameId>`, add `clientFrames` mapping,
implement targeted routing |
|
[src/extension/tab/hook.ts](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/tab/hook.ts:0:0-0:0)
| Add `SKIP_RESPONSE` to `getClients` handler for frames without clients
|
|
[src/extension/tab/handleExplorerRequests.ts](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/src/extension/tab/handleExplorerRequests.ts:0:0-0:0)
| Replace throw with silent return |
|
[development/client/public/iframe.html](cci:7://file:///Users/camillelawrence/Desktop/repos/apollo-client-devtools/development/client/public/iframe.html:0:0-0:0)
| 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

- Closes #380
- Related: PR #828, PR #997

---------

Co-authored-by: Jerel Miller <jerelmiller@gmail.com>
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.

1 participant