How Chromium's Coverage Tab Identifies Unused JS and CSS

This article explains the underlying mechanisms of the Chromium Coverage tab, detailing how it detects unused JavaScript and CSS bytes. By leveraging the V8 JavaScript engine's built-in profiler and the Blink rendering engine's style tracker, Chromium monitors code execution and CSS rule application in real time. This runtime data is then mapped back to the original source file byte ranges via the Chrome DevTools Protocol to calculate and highlight dead code.

The Chrome DevTools Protocol (CDP) Foundation

The Coverage tab does not parse or analyze code on its own. Instead, it acts as a visual interface for data gathered by Chromium’s internal engines. When you start recording in the Coverage tab, DevTools sends commands through the Chrome DevTools Protocol (CDP) to two specific browser components: the V8 engine (for JavaScript) and the Blink rendering engine (for CSS).

Specifically, it triggers the Profiler.startPreciseCoverage method for JavaScript and the CSS.startRuleUsageTracking method for CSS.

Identifying Unused JavaScript via V8

JavaScript coverage is handled entirely by V8, Chromium's JavaScript engine. Before executing JavaScript, V8 parses the downloaded text into an Abstract Syntax Tree (AST) and compiles it into bytecode.

When coverage tracking is enabled, V8 uses a technique called block-level instrumentation:

  1. Bytecode Instrumentation: V8 inserts specialized counters into the generated bytecode. These counters are placed at the boundaries of functions and control-flow branches (such as if/else statements, loops, and switch cases).
  2. Execution Tracking: As you interact with the web page, V8 executes the bytecode. Every time a specific block of code is run, its corresponding counter increments.
  3. Source Mapping: V8 maintains a mapping table that links every bytecode instruction back to the exact character offsets (start and end bytes) in the original JavaScript source file.
  4. Data Collection: When the coverage recording stops, V8 checks the counters. Any block with a counter of zero was never executed. V8 reports the byte ranges of the executed blocks back to the Coverage tab.

Comments and whitespace outside of executed functions are typically ignored or grouped with the surrounding scope, while uncalled functions and untaken conditional branches are flagged as unused bytes.

CSS is declarative, meaning it is not "executed" like JavaScript. Therefore, Chromium's Blink rendering engine tracks CSS coverage by monitoring the browser's rendering lifecycle, specifically the Style Calculation phase.

When CSS coverage is active, Blink performs the following steps:

  1. CSSOM Parsing: Blink parses the downloaded CSS text into the CSS Object Model (CSSOM). During this phase, the engine records the exact start and end byte offsets for every style rule in the original stylesheet.
  2. Rule Matching: As the browser constructs the DOM and calculates the visual styles for elements, it iterates through the CSSOM to see which selectors match actual nodes in the DOM tree.
  3. Flagging Used Rules: If a CSS selector matches at least one DOM element currently on the page, Blink marks that specific rule as "used."
  4. Handling Special Rules: At-rules like @media are evaluated based on the current viewport state. If the media query condition is met, the rules inside are evaluated against the DOM. Keyframes (@keyframes) and font faces (@font-face) are marked as used only if an element on the page actively references them.

Calculating the Dead Bytes

Once the recording ends, the Coverage tab aggregates the data received from V8 and Blink to calculate the final unused byte metrics:

  1. Total Bytes: DevTools knows the exact byte size of each downloaded JavaScript and CSS file from the network layer.
  2. Range Subtraction: The engines provide arrays of used byte ranges (e.g., bytes 0 to 150 were used, bytes 300 to 450 were used).
  3. Visualizing the Diff: The Coverage tab subtracts the used byte ranges from the total byte length of the file. The remaining gaps represent the dead bytes—code that was downloaded over the network and parsed into memory, but never executed by V8 or applied to the DOM by Blink.

In the DevTools source view, used byte ranges are highlighted in green (or blue), while the unreferenced byte ranges are highlighted in red, providing an exact line-by-line breakdown of dead code.