Resource management in DevTools

This document outlines how DevTools keeps track of resources like scripts and HTML files, and how they interact with other features such as the Debugger. The source code lives in the bindings/, persistence/ and workspace/ directories.

Core concepts and classes

  • Project: Interface to a collection of resources. DevTools supports different project types. For example “filesystem”, for resources originating from the developers local machine, and “network”, for actual page resources. The Project interface abstracts away rudimentary file operations. Depending on the type, a Project may be able to create, rename or delete resources, or change the contents.

  • Workspace: A collection of all the Projects currently in use. Implemented as a singleton in WorkspaceImpl.ts.

  • UISourceCode: An actual resource identified by its URL. Scripts and stylesheets are prominent examples, but DevTools also uses more esoteric ResourceTypes such as XHR, WebSocket or EventSource.

Project types

A short overview over the different Project types and what kind of resources they contain.

  • Network: All resources loaded from the network are stored in network projects. Different targets and/or Resource types may use different projects. E.g. Each target has their own project containing only JavaScript source maps.

  • Filesystem: Resources stored on the developers local machine.

    • Snippets are managed with a single Project just for snippets.
    • Each local directory mapped into DevTools with the “Workspaces” feature has its own project.
    • Each directory used for the “Overrides” feature has a corresponding project to manage the local files.
  • Formatter: A single project of this type manages the formatted version of script resources. That is the “pretty-print” feature for minified JS files.

  • ContentScripts: Scripts from extensions running in the context of the page itself. One project per target. Source maps for content scripts are managed by separate, per target, projects. The source map projects also have the ContentScripts type.

  • Service: One project of this type per target. It holds placeholder UISourceCodes for source maps while they are loaded. Once a source map finishes loading, the placeholder is removed from the Service project.

  • Debugger: One project of this type per target. Debugger projects store parsed JS scripts (see next section).

The “Debugger” project type

When V8 parses scripts, it sends out a “Debugger.ScriptParsed” event with some details, including a unique script ID and the URL of the script. For each “Debugger.ScriptParsed” event, DevTools creates a Script object and an associated UISourceCode in the “debugger” project. It is important to note that the URL of this “debugger” UISourceCode contains both the script ID as well as the script name (not URL!) to uniquely identify it. This is because:

The relationship between network/filesystem UISourceCodes and Script objects/debugger UISourceCodes is 1:n.

For example if the same script is included twice on a page with <script> elements, it will result in a single UISourceCode in the Network project but two Script objects and two UISourceCodes in the Debugger project. Similarly, every invocation of a Snippet will result in a separate Script object per invocation while the Snippet itself is stored in a Filesystem project.

Mappings and bindings

As can be seen above, UISourceCodes in different projects can potentially be related to one another. A minified script resource in a scripts Network project might have a pretty-printed version in the Formatter project while the source map for the minified script is stored in the source map Network project. Once the minified script is parsed/executed by V8, it also has a corresponding Script object and a UISourceCode in the Debugger project.

This brings us to mappings and bindings. The terminology is roughly:

  • A binding ties different UISourceCodes together and determines which UISourceCodes relate to one another.
  • A mapping translates source positions between bound UISourceCodes.

Binding implementations

There are a couple of classes tasked with establishing bindings between UISourceCodes:

  • DebuggerWorkspaceBinding: Responsible for scripts and source maps. It ties together network/filesystem UISourceCodes with Script objects and the debugger USourceCodes. Script source maps are also partially implemented by this class.

  • CSSWorkspaceBinding: Responsible for CSS and CSS source maps. DevTools can handle source mapped CSS when it was authored in SASS and this class is responsible for binding the corresponding UISourceCodes.

  • PersistenceBinding/PersistenceImpl/Automapping: Responsible for the “Workspaces” feature. When a developer adds a local directory to DevTools that corresponds to the pages sources, these classes establish and manage the binding between the corresponding Filesystem and Network resources.

  • NetworkPersistenceManager: Responsible for the “Local Overrides” feature. It connects the Network resources with the corresponding overwritten version in a Filesystem project. This class also handles network request interceptions and determines whether to serve the original or the overwritten UISourceCode.

Please keep in mind that many of these classes have gathered additional responsibilities over the years, so the concepts presented above might not always cleanly apply or be apparent in code.