Skip to content

Conversation

@atbrakhi
Copy link
Member

@atbrakhi atbrakhi commented Apr 16, 2025

This patch adds support for listing worker scripts in debugger > source panel

For example:

<!-- test.html -->
<!doctype html><meta charset=utf-8>
<script>
    setTimeout(() => {
        console.log("inline classic");
        new Worker("worker.js");
        
        const blob = new Blob([`console.log("blob worker");`], { type: "text/javascript" });
        const blobURL = URL.createObjectURL(blob);
        new Worker(blobURL);
    }, 2000);
</script>
// worker.js
console.log("external classic worker");
./mach run --devtools=6080 http://127.0.0.1:3000/test.html

file1

Another example:

./mach run --devtools=6080 https://charming.daz.cat/ 

blob

@atbrakhi atbrakhi marked this pull request as ready for review April 17, 2025 08:43
@atbrakhi atbrakhi requested a review from gterzian as a code owner April 17, 2025 08:43
@atbrakhi atbrakhi requested a review from delan April 17, 2025 08:43
github-merge-queue bot pushed a commit that referenced this pull request Apr 21, 2025
…hread` (#36631)

This is part of #36562, where I
discovered that we are sending thread as `context` and `id` for worker
is called `worked_id`. In this PR, I have renamed the `worker_id` to
`id` and thread is sent as `thread` and not context. These chages were
tested in #36562

Some logs for context(this logs are from firefox instance)

`worker_id` should be `id`
```
{"_from": "server1.conn0.watcher35", "message": {"from": "server1.conn0.watcher35", "target": {"actor": "server1.conn0.watcher34.process7//workerTarget21/workerTarget5", "consoleActor": "server1.conn0.watcher34.process7//workerTarget21/console2", "id": "f454ea34-c76a-4b6e-a079-43ee3128881e", "name": "", "objectsManagerActor": "server1.conn0.watcher34.process7//workerTarget21/objects-manager4", "relatedDocumentInnerWindowId": 15032385539, "targetType": "worker", "threadActor": "server1.conn0.watcher34.process7//workerTarget21/thread1", "tracerActor": "server1.conn0.watcher34.process7//workerTarget21/tracer3", "traits": {"supportsTopLevelTargetFlag": false}, "type": 0, "url": "http://localhost:8000/Documents/codespace/servo/worker.js"}, "type": "target-available-form"}}
```

Thread should be `thread` and not `context`
```
{"_from": "server1.conn0.watcher35", "message": {"from": "server1.conn0.watcher35", "target": {"actor": "server1.conn0.watcher34.process7//workerTarget21/workerTarget5", "consoleActor": "server1.conn0.watcher34.process7//workerTarget21/console2", "id": "f454ea34-c76a-4b6e-a079-43ee3128881e", "name": "", "objectsManagerActor": "server1.conn0.watcher34.process7//workerTarget21/objects-manager4", "relatedDocumentInnerWindowId": 15032385539, "targetType": "worker", "threadActor": "server1.conn0.watcher34.process7//workerTarget21/thread1", "tracerActor": "server1.conn0.watcher34.process7//workerTarget21/tracer3", "traits": {"supportsTopLevelTargetFlag": false}, "type": 0, "url": "http://localhost:8000/Documents/codespace/servo/worker.js"}, "type": "target-available-form"}}
```


- [x] ./mach build -d does not report any errors
- [x] ./mach test-tidy does not report any errors
- [x] These changes partially implement
#36027

Signed-off-by: atbrakhi <atbrakhi@igalia.com>
@atbrakhi atbrakhi requested a review from mrobinson April 23, 2025 07:58
Comment on lines 234 to 226
let _ = chan.send(ScriptToDevtoolsControlMsg::ScriptSourceLoaded(
pipeline_id,
Some(worker_id),
worker_source_info,
));
Copy link
Member

Choose a reason for hiding this comment

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

I would send both URLs unconditionally as part of SourceInfo as well as a boolean indicating if this is a worker or not. Then the URL calculation should be done in the devtools part. It's really unclear to me why a particular URL is used here as well. The logic seems to be:

  • If URL is blob:
    • If blob parsing succeeds, use blob UUID
    • Otherwise, use worker URL
  • Otherwise use script URL

Why aren't you falling back to the script URL when blob parsing fails?

Copy link
Member Author

@atbrakhi atbrakhi Apr 23, 2025

Choose a reason for hiding this comment

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

@mrobinson thanks for the review. let me try to answer your questions.

I would send both URLs unconditionally as part of SourceInfo as well as a boolean indicating if this is a worker or not

For worker case we will always get url from worker.rs and for non-worker case we will get the url from htmlscriptelement.rs, I am not sure why we need the boolean indication

Then the URL calculation should be done in the devtools part. It's really unclear to me why a particular URL is used here as well

Oh, this crossed my mind and ideally I would have loved to handle it on devtools side but let me try to explain why I decided to do it this way:

It's mostly because of what script_url and worker_url results in both cases! For a normal worker file like test.html in description:

script_url =  USVString("worker.js")

but for a blob url (like https://charming.daz.cat/ )

script_url = USVString("blob:https://charming.daz.cat/e4a6cdd9-6d11-4382-9621-eee4f252bd1a")

In both case worker_url is:

worker_url: "http://127.0.0.1:8000/worker.js"
worker_url: "blob:https://charming.daz.cat/e4a6cdd9-6d11-4382-9621-eee4f252bd1a"

Firefox client expects worker.js for first case and b38f182a-81d8-4ca1-9458-81d51a3b702b for second case.

Devtools needs the worker_id( i.e b38f182a-81d8-4ca1-9458-81d51a3b702b) and on script side we have functions to parse the url and get the id(parse_blob_url). Hence it was more straight forward to handle this on worker.rs file itslef. Handling it on devtools side would have required extra logic/code.

Copy link
Member

Choose a reason for hiding this comment

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

Does Firefox have the same behavior for all blob URLs? For example, in the non-worker case what does Firefox do with a <script> that is a blob URL?

Copy link
Member Author

@atbrakhi atbrakhi Apr 23, 2025

Choose a reason for hiding this comment

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

No. Looking at the logs, client expectations are different for blob URL in worker and non-worker case:

For non-worker case, this is the logs (note that it doesn't expects id but only url "url": "blob:null/2c28e98c-0da2-4198-860a-c72e20b4a49b"})

{"_from": "server1.conn1.watcher34.process9//windowGlobalTarget2", "message": {"array": [["console-message", [{"arguments": ["hello blob script."], "columnNumber": 9, "filename": "blob:null/2c28e98c-0da2-4198-860a-c72e20b4a49b", "innerWindowID": 19327352833, "level": "log", "lineNumber": 1, "sourceId": null, "timeStamp": 1745401545017.463}]]], "from": "server1.conn1.watcher34.process9//windowGlobalTarget2", "type": "resources-available-array"}}
{"_from": "server1.conn1.watcher34.process9//windowGlobalTarget2", "message": {"array": [["source", [{"actor": "server1.conn1.watcher34.process9//source20", "extensionName": null, "introductionType": "scriptElement", "isBlackBoxed": false, "isInlineSource": true, "sourceLength": 287, "sourceMapBaseURL": "file:///Users/atbrakhi/Documents/codespace/servo/test.html", "sourceMapURL": null, "sourceStartColumn": 10, "sourceStartLine": 4, "url": "file:///Users/atbrakhi/Documents/codespace/servo/test.html"}, {"actor": "server1.conn1.watcher34.process9//source21", "extensionName": null, "isBlackBoxed": false, "isInlineSource": false, "sourceLength": 48, "sourceMapBaseURL": null, "sourceMapURL": null, "sourceStartColumn": 0, "sourceStartLine": 1, "url": "blob:null/2c28e98c-0da2-4198-860a-c72e20b4a49b"}]]], "from": "server1.conn1.watcher34.process9//windowGlobalTarget2", "type": "resources-available-array"}}

For worker case (note that it expects both "id": "f454ea34-c76a-4b6e-a079-43ee3128881e" and url "url": "http://localhost:8000/Documents/codespace/servo/worker.js". Just sending the sourceInfo is not enough here)

{"_from": "server1.conn0.watcher35", "message": {"from": "server1.conn0.watcher35", "target": {"actor": "server1.conn0.watcher34.process7//workerTarget21/workerTarget5", "consoleActor": "server1.conn0.watcher34.process7//workerTarget21/console2", "id": "f454ea34-c76a-4b6e-a079-43ee3128881e", "name": "", "objectsManagerActor": "server1.conn0.watcher34.process7//workerTarget21/objects-manager4", "relatedDocumentInnerWindowId": 15032385539, "targetType": "worker", "threadActor": "server1.conn0.watcher34.process7//workerTarget21/thread1", "tracerActor": "server1.conn0.watcher34.process7//workerTarget21/tracer3", "traits": {"supportsTopLevelTargetFlag": false}, "type": 0, "url": "http://localhost:8000/Documents/codespace/servo/worker.js"}, "type": "target-available-form"}}

Copy link
Member Author

Choose a reason for hiding this comment

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

I have created #36727 for this issue

Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Signed-off-by: atbrakhi <atbrakhi@igalia.com>
Copy link
Member

@mrobinson mrobinson left a comment

Choose a reason for hiding this comment

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

Looks good with one change before landing. Thanks!

Comment on lines 217 to 225
let source_info = SourceInfo {
url: worker_url.clone(),
external: true, // Worker scripts are always external.
};
let _ = chan.send(ScriptToDevtoolsControlMsg::ScriptSourceLoaded(
pipeline_id,
Some(worker_id),
source_info,
));
Copy link
Member

Choose a reason for hiding this comment

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

I think that Option<WorkerId> should be part of SourceInfo instead of the message itself as SourceInfo should include all information about the source.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree that SourceInfo should include all the information about the source, and we are sending all information in to the client but I am not sure we should include the worker_id in the sourceInfo struct itself. Some reasons for that:

  • SourceInfo represents information abouts source code itself(not only specific to worker, could be for both frame and worker and in future for something else as well), this struct will grow with upcoming work related to source panel and will have more fields
  • worker_id is more of representation for the exectiation context and is not only* specific to sources. In this PR yes, they are realted, but if we consider the whole devtools, worker_id allows us to follow the seperation of concern, as in information about the source is separate from information about where it is running and for what.
  • existing code in browsing_context also follows this seperation, and i think we should continue that.

Not sure if you meant something else, am I missing something?

Copy link
Member

@mrobinson mrobinson Apr 29, 2025

Choose a reason for hiding this comment

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

I don't see how something like external: bool is very different in this case from worker_id: Option<WorkerId>. In the end SourceInfo is the payload of this message. The message payload should all be in the same data structure or all be in the body of the message. Splitting it between two things somewhat arbitrarily doesn't make sense to me.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, sorry, I misunderstood your comment. I saw your suggestion as worker_id should be part of SourceInfo in all places, and that confused me.

Thanks for clarifying, 0b30138 updates the SourceInfo struct to include worker_id

Signed-off-by: atbrakhi <atbrakhi@igalia.com>
@atbrakhi atbrakhi enabled auto-merge April 29, 2025 08:14
@atbrakhi atbrakhi added this pull request to the merge queue Apr 29, 2025
Merged via the queue into servo:main with commit b92542b Apr 29, 2025
21 checks passed
@atbrakhi atbrakhi deleted the sources_worker branch April 29, 2025 09:42
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