Skip to content

Commit 26a2acd

Browse files
committed
[Web Inspector] Add Debugging guide for Inspector frontend development
Port and modernize the WebInspectorDebugging wiki page from trac.webkit.org. Organized around common problems developers encounter: - Fast JS-only rebuilds (make -C Source/WebInspectorUI/) - Protocol message tracing (Debug UI toggle, settings, programmatic flags) - Inspecting the Inspector (Inspector^2 via Debug UI or Settings) - Debugging failing layout tests (InspectorTest.debug(), forceDebugLogging) - Readable stack traces (COMBINE_INSPECTOR_RESOURCES=NO) - C++ backend debugging (process identification, logging channels) - iOS Simulator debugging - Engineering and Debug settings reference - Quick reference table All commands and preference keys verified against current WebKit source.
1 parent 16392cd commit 26a2acd

1 file changed

Lines changed: 240 additions & 0 deletions

File tree

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# Debugging Web Inspector
2+
3+
This guide covers techniques for debugging the Web Inspector frontend itself -- the JavaScript application that provides WebKit's developer tools UI. It is organized around problems you will encounter when developing and testing Web Inspector.
4+
5+
Throughout this guide, "engineering build" means a Debug or Release build where `COMBINE_INSPECTOR_RESOURCES=NO`. The `Debug/Bootstrap.js` file is included and sets `WI.isEngineeringBuild = true`, which enables Engineering and Debug settings panes, the Debug UI toggle, and the "inspect inspector" button. Production builds combine all JS/CSS into `Main.js`/`Main.css` and strip the `Debug/` directory entirely.
6+
7+
## "My change isn't showing up"
8+
9+
You edited a JavaScript or CSS file under `Source/WebInspectorUI/UserInterface/`, but Web Inspector still shows the old behavior.
10+
11+
**Root cause:** Inspector frontend files are copied from the source tree into the framework bundle during the build. Editing a source file does not update the running copy.
12+
13+
**Fast JS-only rebuild:**
14+
15+
```bash
16+
make -C Source/WebInspectorUI/
17+
```
18+
19+
This invokes `copy-user-interface-resources.pl` to re-copy files. It completes nearly instantly because no compilation is involved -- just file copies via `ditto`. This is dramatically faster than a full `make GROUP=webkit debug` (~60 seconds).
20+
21+
After rebuilding, reload the Inspector to pick up changes:
22+
23+
- Press **Option + Shift + Command + R** (calls `InspectorFrontendHost.reopen()`)
24+
- Or right-click in the Inspector (with Debug UI enabled) and choose **"Reload Web Inspector"**
25+
26+
**When you need a full rebuild:** If you changed C++ code in `Source/WebKit/`, `Source/WebCore/inspector/`, or `Source/JavaScriptCore/inspector/`, use `make GROUP=webkit debug`.
27+
28+
## "I need to see protocol messages"
29+
30+
You suspect protocol commands are not being sent, events are not arriving, or parameters are wrong.
31+
32+
### Option 1: Debug UI toggle (engineering builds)
33+
34+
1. Press **Option + Shift + Command + D** to reveal the Debug UI.
35+
2. Click the **console icon button** in the tab bar:
36+
- **Click** = filtered logging (hides `(multi)` target messages).
37+
- **Shift-click** = unfiltered logging (shows everything). Button turns **purple**.
38+
- **Click again** = off.
39+
40+
Messages appear in the Inspector console. To view them, open Inspector^2 (see below).
41+
42+
### Option 2: Settings tab (engineering builds)
43+
44+
Open Settings (gear icon). Under **Debug > Protocol Logging:**
45+
46+
| Setting | Effect |
47+
|---------|--------|
48+
| **Messages** | Logs all protocol messages (`InspectorBackend.dumpInspectorProtocolMessages`) |
49+
| **Time Stats** | Adds RTT and dispatch timing per message |
50+
| **Log as Text** | Forces JSON strings instead of expandable objects |
51+
52+
### Option 3: Programmatic flags
53+
54+
```javascript
55+
InspectorBackend.dumpInspectorProtocolMessages = true;
56+
InspectorBackend.filterMultiplexingBackendInspectorProtocolMessages = false;
57+
InspectorBackend.dumpInspectorTimeStats = true;
58+
```
59+
60+
Each logged message is formatted by `LoggingProtocolTracer` as:
61+
62+
```
63+
request (page-1): {"id":42,"method":"DOM.getDocument","params":{}}
64+
response (page-1): {"id":42,"result":{"root":{...}}}
65+
event (page-1): {"method":"DOM.documentUpdated","params":{}}
66+
```
67+
68+
Target identifiers: `(multi)` = multiplexing backend, `(page-N)` = page target, `(frame-N)` = frame target (Site Isolation), `(worker-N)` = worker target.
69+
70+
### Option 4: Capture a protocol trace
71+
72+
In engineering builds with Debug UI enabled, right-click > **Protocol Debugging > Capture Trace**. Perform actions, then right-click > **Export Trace...** to save as JSON.
73+
74+
## "I need to set a breakpoint in Inspector JS code"
75+
76+
Web Inspector is itself a web page rendered by a WKWebView. You can open a second instance to debug the first ("Inspector^2").
77+
78+
### Method 1: Debug UI button (engineering builds)
79+
80+
1. Open Web Inspector on any page.
81+
2. Press **Option + Shift + Command + D** to enable Debug UI.
82+
3. Click the **numbered button** in the tab bar (shows "2"). A new Inspector window opens.
83+
84+
Under the hood, the button calls `InspectorFrontendHost.inspectInspector()`, which enables `developerExtrasEnabled` on the Inspector's page and opens a new inspector controller.
85+
86+
### Method 2: Settings (all builds)
87+
88+
Open Settings > **Experimental** > check **"Allow Inspecting Web Inspector"**. In engineering builds, the numbered button appears in Debug UI. In non-engineering builds, use Safari's **Develop** menu -- the Inspector's WebContent process appears as an inspectable target.
89+
90+
### Method 3: defaults write (release builds)
91+
92+
```bash
93+
defaults write com.apple.Safari WebKitDebugWebInspectorEngineeringSettingsAllowed -bool true
94+
```
95+
96+
### Inspection levels
97+
98+
Each nested inspector has an `inspectionLevel` property (via `InspectorFrontendHost.inspectionLevel`). Level 1 is the normal Inspector; level 2 is Inspector^2. Each level gets its own preferences namespace, so settings do not collide.
99+
100+
## "My test is timing out"
101+
102+
Inspector layout tests are asynchronous. Common timeout causes: waiting for events that never fire (wrong event name or wrong class), unresolved promises, or silently swallowed exceptions.
103+
104+
### Step 1: Enable debug logging
105+
106+
Call `InspectorTest.debug()`:
107+
108+
```javascript
109+
function test()
110+
{
111+
InspectorTest.debug();
112+
// ... rest of test
113+
}
114+
```
115+
116+
This enables both `dumpActivityToSystemConsole` (tees output to stderr) and `dumpInspectorProtocolMessages` (logs all protocol traffic).
117+
118+
For maximum visibility, set all flags individually:
119+
120+
```javascript
121+
InspectorTest.forceDebugLogging = true;
122+
InspectorTest.dumpActivityToSystemConsole = true;
123+
InspectorBackend.dumpInspectorProtocolMessages = true;
124+
InspectorBackend.filterMultiplexingBackendInspectorProtocolMessages = false;
125+
```
126+
127+
| Flag | Effect |
128+
|------|--------|
129+
| `forceDebugLogging` | Routes `log()` through `debugLog()` (synchronous stderr). Survives timeouts. |
130+
| `dumpActivityToSystemConsole` | Tees `addResult`, `completeTest` calls to stderr |
131+
| `dumpInspectorProtocolMessages` | Logs every protocol message to stderr |
132+
| `filterMultiplexingBackendInspectorProtocolMessages` | When `false`, includes `(multi)` messages |
133+
134+
For **protocol tests**: use `ProtocolTest.debug()` or the equivalent `ProtocolTest.*` flags.
135+
136+
### Step 2: Verify event names exist
137+
138+
```bash
139+
grep -r "WI.Frame.Event.ExecutionContextChanged" Source/WebInspectorUI/
140+
```
141+
142+
If zero results, the event does not exist on that class. Check adjacent classes -- naming is inconsistent (e.g., `WI.Frame.Event` vs. `WI.FrameTarget.Event` vs. `WI.Target.Event`).
143+
144+
## "I can't read the stack traces"
145+
146+
Stack frames reference `Main.js` at high line numbers, or all Inspector code appears in a single file.
147+
148+
**Root cause:** The build combined all JavaScript into `Main.js`. Controlled by:
149+
150+
| Setting | Base.xcconfig (Production) | DebugRelease.xcconfig (Engineering) |
151+
|---------|---------------------------|-------------------------------------|
152+
| `COMBINE_INSPECTOR_RESOURCES` | `YES` | `NO` |
153+
| `COMBINE_TEST_RESOURCES` | `NO` | `YES` |
154+
155+
Note the inversion: engineering builds keep Inspector resources separate but combine test resources.
156+
157+
**Solution:** Use a Debug or Release engineering build.
158+
159+
## "I need to debug Inspector C++ backend code"
160+
161+
### Identifying the correct process
162+
163+
| Code location | Process |
164+
|--------------|---------|
165+
| `Source/WebKit/UIProcess/Inspector/` | UI Process (Safari/MiniBrowser) |
166+
| `Source/WebCore/inspector/agents/` | Inspected WebContent Process |
167+
| `Source/WebKit/WebProcess/Inspector/WebInspectorUI.cpp` | Inspector's own WebContent Process |
168+
| `Source/JavaScriptCore/inspector/` | WebContent Process (JSC layer) |
169+
170+
### System console logging
171+
172+
In debug builds, Inspector `console.log()` output is routed to the system console automatically. For release builds:
173+
174+
```bash
175+
defaults write com.apple.Safari WebKitDebugLogsPageMessagesToSystemConsoleEnabled -bool true
176+
```
177+
178+
### WebKit logging channels
179+
180+
```bash
181+
defaults write com.apple.Safari WebKit2Logging "Inspector=debug"
182+
defaults write com.apple.Safari WebCoreLogging "Inspector=debug"
183+
```
184+
185+
Replace `com.apple.Safari` with the appropriate bundle identifier.
186+
187+
## Debugging in iOS Simulator
188+
189+
1. Build: `Tools/Scripts/build-webkit --debug --ios-simulator`
190+
2. Launch: `Tools/Scripts/run-safari --debug --ios-simulator`
191+
3. On Mac, open Safari > **Develop > Simulator** to see inspectable pages.
192+
193+
The Inspector frontend runs on macOS, connecting via the remote inspector protocol (`RemoteWebInspectorUI`/`RemoteWebInspectorUIProxy`).
194+
195+
## Engineering and Debug settings reference
196+
197+
### Engineering pane
198+
199+
Available when `WI.engineeringSettingsAllowed()` returns true:
200+
201+
| Setting | Description |
202+
|---------|-------------|
203+
| Allow editing UserAgent shadow trees | Permits DOM editing of browser-generated shadow DOM |
204+
| Show WebKit-internal execution contexts | Reveals internal contexts in the console picker |
205+
| Show WebKit-internal scripts | Shows internal scripts in the Sources tab |
206+
| Pause in WebKit-internal scripts | Allows breakpoints in internal scripts |
207+
| Show Internal Objects (Heap Snapshot) | Displays JSC-internal heap objects |
208+
| Show Private Symbols (Heap Snapshot) | Displays private symbol properties |
209+
210+
### Debug pane
211+
212+
Available in engineering builds when Debug UI is enabled (Option + Shift + Command + D):
213+
214+
| Setting | Description |
215+
|---------|-------------|
216+
| Messages | Log all protocol messages to console |
217+
| Time Stats | Log protocol message timing data |
218+
| Log as Text | Force JSON text output instead of structured objects |
219+
| Outline focused element | Draw outline around focused Inspector UI element |
220+
| Layout Flashing | Draw borders when views perform layout |
221+
| Style editing debug mode | Enable verbose CSS editing logging |
222+
| Report Uncaught Exceptions | Show dialog on uncaught frontend exceptions |
223+
| Layout Direction | Override layout direction (LTR/RTL/System) |
224+
225+
## Quick reference
226+
227+
| I want to... | Do this |
228+
|--------------|---------|
229+
| Rebuild after changing Inspector JS/CSS | `make -C Source/WebInspectorUI/` |
230+
| Rebuild after changing Inspector C++ | `make GROUP=webkit debug` |
231+
| Reload Inspector without restarting page | Option + Shift + Cmd + R |
232+
| Toggle Debug UI | Option + Shift + Cmd + D |
233+
| See protocol messages interactively | Debug UI > click console icon |
234+
| See protocol messages in a test | `InspectorTest.debug()` or `ProtocolTest.debug()` |
235+
| Debug Inspector JS with a debugger | Settings > Experimental > "Allow Inspecting Web Inspector" |
236+
| Get readable stack traces | Use a Debug or Release build (`COMBINE_INSPECTOR_RESOURCES=NO`) |
237+
| Enable C++ logging | `defaults write <bundle-id> WebKit2Logging "Inspector=debug"` |
238+
| Enable engineering settings in release | `defaults write <bundle-id> WebKitDebugWebInspectorEngineeringSettingsAllowed -bool true` |
239+
| Verify an event name exists | `grep -r "WI.ClassName.Event.Name" Source/WebInspectorUI/` |
240+
| Capture protocol traffic to file | Debug UI > right-click > Protocol Debugging > Capture Trace |

0 commit comments

Comments
 (0)