Simon Zünd | a6dbaac | 2022-01-26 15:12:52 | [diff] [blame] | 1 | # Resource management in DevTools |
| 2 | |
| 3 | This document outlines how DevTools keeps track of resources like scripts and |
| 4 | HTML files, and how they interact with other features such as the Debugger. |
| 5 | The source code lives in the bindings/, persistence/ and workspace/ directories. |
| 6 | |
| 7 | ## Core concepts and classes |
| 8 | |
| 9 | * **Project:** Interface to a collection of resources. DevTools supports |
| 10 | different project **types**. For example “filesystem”, for resources |
| 11 | originating from the developers local machine, and “network”, for actual page |
| 12 | resources. The **Project** interface abstracts away rudimentary file |
| 13 | operations. Depending on the **type**, a **Project** may be able to create, |
| 14 | rename or delete resources, or change the contents. |
| 15 | |
| 16 | * **Workspace**: A collection of all the **Projects** currently in use. |
| 17 | Implemented as a singleton in WorkspaceImpl.ts. |
| 18 | |
| 19 | * **UISourceCode:** An actual resource identified by its URL. Scripts and |
| 20 | stylesheets are prominent examples, but DevTools also uses more esoteric |
| 21 | **ResourceTypes** such as XHR, WebSocket or EventSource. |
| 22 | |
| 23 | ## Project types |
| 24 | |
| 25 | A short overview over the different Project types and what **kind of resources** |
| 26 | they contain. |
| 27 | |
| 28 | * **Network:** All resources loaded from the network are stored in network |
| 29 | projects. Different targets and/or **Resource** **types** may use different |
| 30 | projects. E.g. Each target has their own project containing only JavaScript |
| 31 | source maps. |
| 32 | |
| 33 | * **Filesystem:** Resources stored on the developers local machine. |
| 34 | * Snippets are managed with a single Project just for snippets. |
| 35 | * Each local directory mapped into DevTools with the “Workspaces” feature has |
| 36 | its own project. |
| 37 | * Each directory used for the “Overrides” feature has a corresponding project |
| 38 | to manage the local files. |
| 39 | |
| 40 | * **Formatter:** A single project of this type manages the formatted version of |
| 41 | script resources. That is the “pretty-print” feature for minified JS files. |
| 42 | |
| 43 | * **ContentScripts**: Scripts from extensions running in the context of the page |
| 44 | itself. One project per target. Source maps for content scripts are managed by |
| 45 | separate, per target, projects. The source map projects also have the |
| 46 | **ContentScripts** type. |
| 47 | |
| 48 | * **Service:** One project of this type per target. It holds placeholder |
| 49 | UISourceCodes for source maps while they are loaded. Once a source map |
| 50 | finishes loading, the placeholder is removed from the **Service** project. |
| 51 | |
| 52 | * **Debugger:** One project of this type per target. Debugger projects store |
| 53 | parsed JS scripts (see next section). |
| 54 | |
| 55 | ## The “Debugger” project type |
| 56 | |
| 57 | When V8 parses scripts, it sends out a |
| 58 | [“Debugger.ScriptParsed”](https://chromedevtools.github.io/devtools-protocol/tot/Debugger/#event-scriptParsed) |
| 59 | event with some details, including a unique script ID and the URL of the script. |
| 60 | For each “Debugger.ScriptParsed” event, DevTools creates a **Script** object and |
| 61 | an associated **UISourceCode** in the “debugger” project. It is important to |
| 62 | note that the URL of this “debugger” UISourceCode contains both the script ID as |
| 63 | well as the script name (not URL!) to uniquely identify it. This is because: |
| 64 | |
| 65 | _The relationship between network/filesystem UISourceCodes and **Script** |
| 66 | **objects**/debugger UISourceCodes is 1:n._ |
| 67 | |
| 68 | For example if the same script is included twice on a page with <script> |
| 69 | elements, it will result in a single UISourceCode in the **Network** project but |
| 70 | **two Script** **objects** and two UISourceCodes in the **Debugger** project. |
| 71 | Similarly, every invocation of a Snippet will result in a separate **Script** |
| 72 | object per invocation while the Snippet itself is stored in a **Filesystem** |
| 73 | project. |
| 74 | |
| 75 | ## Mappings and bindings |
| 76 | |
| 77 | As can be seen above, UISourceCodes in different projects can potentially be |
| 78 | related to one another. A minified script resource in a **scripts Network project** |
| 79 | might have a pretty-printed version in the **Formatter project** while the |
| 80 | source map for the minified script is stored in the **source map Network project**. |
| 81 | Once the minified script is parsed/executed by V8, it also has a corresponding |
| 82 | **Script object** and a UISourceCode in the **Debugger project**. |
| 83 | |
| 84 | This brings us to mappings and bindings. The terminology is roughly: |
| 85 | |
| 86 | * _A **binding** ties different UISourceCodes together and determines which |
| 87 | UISourceCodes relate to one another._ |
| 88 | * _A **mapping** translates source positions between bound UISourceCodes._ |
| 89 | |
| 90 | ## Binding implementations |
| 91 | |
| 92 | There are a couple of classes tasked with establishing bindings between |
| 93 | UISourceCodes: |
| 94 | |
| 95 | * **DebuggerWorkspaceBinding:** Responsible for scripts and source maps. |
| 96 | It ties together network/filesystem UISourceCodes with **Script** objects and |
| 97 | the debugger USourceCodes. Script source maps are also partially implemented |
| 98 | by this class. |
| 99 | |
| 100 | * **CSSWorkspaceBinding:** Responsible for CSS and CSS source maps. DevTools can |
| 101 | handle source mapped CSS when it was authored in SASS and this class is |
| 102 | responsible for binding the corresponding UISourceCodes. |
| 103 | |
| 104 | * **PersistenceBinding/PersistenceImpl/Automapping**: Responsible for the |
| 105 | [“Workspaces”](https://developer.chrome.com/docs/devtools/workspaces/) |
| 106 | feature. When a developer adds a local directory to DevTools that corresponds |
| 107 | to the pages sources, these classes establish and manage the binding between |
| 108 | the corresponding **Filesystem** and **Network** resources. |
| 109 | |
| 110 | * **NetworkPersistenceManager**: Responsible for the |
| 111 | [“Local Overrides”](https://developer.chrome.com/blog/new-in-devtools-65/#overrides) |
| 112 | feature. It connects the **Network** resources with the corresponding |
| 113 | overwritten version in a **Filesystem** project. This class also handles |
| 114 | network request interceptions and determines whether to serve the original or |
| 115 | the overwritten UISourceCode. |
| 116 | |
| 117 | Please keep in mind that many of these classes have gathered additional |
| 118 | responsibilities over the years, so the concepts presented above might not |
| 119 | always cleanly apply or be apparent in code. |