chrome-remote-interface
chrome-remote-interface copied to clipboard
How to properly handle iframe "swaps" (FrameDetached, Reason "swap")?
Environment
| Component | Version |
|---|---|
| Node.js | v18.12.0 |
| Client (Chrome/Chromium/...) | 124.0.6367.79 |
| OS running Node.js | Windows 11 |
| OS running the client | Windows 11 |
| chrome-remote-interface | v0.33.0 |
Is the client running in a container? NO
Description
I am trying to read all frames via Page.getFrameTree(). It works at the start. The frames are all visible. But after a short moment a FrameDetached, Reason: swap-event is fired.
Now the question is, how to “handle” this correctly?
http://127.0.0.1:9222/json/list shows the correct IFrames. However, Page.getFrameTree() does not - although I would expect it to.
Unfortunately, this topic has not (yet) been dealt with here. Puppeteer seems to have found a way to do this, but I couldn't find the right place in the code base. Probably because Puppeteer pays attention to Target.targetCreated at the same time?
It also feels as if the IFrame is a “separate process”. If I connect directly via CDP({ target: webSocketDebuggerUrl }) (while webSocketDebuggerUrl is the url to the IFrame; parentId is the page which contains that IFrame), then it works.
Example
const CDP = require('chrome-remote-interface');
async function main() {
// I don't have an example (yet).
}
main().catch((error) => {
console.error(error);
});
Running Chrome with --disable-site-isolation-trials helps here. But I doubt that this is the "best" way.
I already can see that. The whole topic has already been discussed and my “feeling” has somehow been confirmed. It's probably about “OOPIFs” and that makes the story quite complex. Has anyone perhaps already realized this with chrome-remote-interface?
Well, the protocol is the same, so whatever works in Puppeteer, should work here too. The protocol however is complex, mostly experimental, and I have nothing to do with that. Whenever I face similar issues I just read the terrible documentation available and I proceed by trials and errors.
Having said that, it's not clear to me what your problem is... You can register for events and react the way you want. You can CDP.List targets and connect to them. However if you plan to interact with multiple targets, I think it's better to connect to the browser target, certain things are not available via regular targets IIRC.
My issue is/was, that Chrome is going to isolate iframes for different origins. So they're getting detached ("swap"), but before a new target is getting created (with the same ID). So, instead of being a part of a website, it'll get it's own target. I simply created a Map<frameId, cdpClient>() and I'm listening on targetCreated and frameDetached events. Once a target is created and a frame is detached (reason: swap) with the same ID, I create a new connection with CDP to that target and I update the cdpClient in the Map. It's pretty ugly and I don't like it. I was digging into Puppeteer and Playwright to see how they've managed it and it's almost the same. There is a Chromium flag to disable this kind of isolation, but that's ugly, too. :D