Skip to content

Commit a823c64

Browse files
authored
Merge branch 'main' into users/devanb/landingView
2 parents 3b5cee8 + a7e4f59 commit a823c64

File tree

9 files changed

+141
-26
lines changed

9 files changed

+141
-26
lines changed

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212

1313
<!-- Pick one: -->
1414

15-
- [ ] This commit should be sent as a patch to the upstream `devtools-frontend` repo. I've reviewed the [contribution guide](https://docs.google.com/document/d/1WNF-KqRSzPLUUfZqQG5AFeU_Ll8TfWYcJasa_XGf7ro/edit#heading=h.9kj7femz1xg5).
15+
- [ ] This commit should be sent as a patch to the upstream `devtools-frontend` repo following the [contribution guide for Meta employees](https://fburl.com/wiki/43s6yft1) OR [contribution guide](https://chromium.googlesource.com/devtools/devtools-frontend/+/main/docs/contributing/README.md).
1616
- [ ] This commit is React Native-specific and cannot be upstreamed.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ This repository is a fork of [ChromeDevTools/devtools-frontend](https://github.c
1919

2020
### Build-and-run options
2121

22+
Run prebuild to set up the out dir:
23+
```
24+
npm run prebuild
25+
```
26+
2227
1. Build continuously with a file watcher:
2328
2429
```sh

front_end/core/host/RNPerfMetrics.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class RNPerfMetrics {
3030
// map of panel location to panel name
3131
#currentPanels = new Map<PanelLocation, string>();
3232

33+
isEnabled(): boolean {
34+
return globalThis.enableReactNativePerfMetrics === true;
35+
}
36+
3337
addEventListener(listener: RNReliabilityEventListener): UnsubscribeFn {
3438
this.#listeners.add(listener);
3539

@@ -259,6 +263,15 @@ class RNPerfMetrics {
259263
});
260264
}
261265

266+
stackTraceSymbolicationSucceeded(specialHermesFrameTypes: string[]): void {
267+
this.sendEvent({
268+
eventName: 'StackTraceSymbolicationSucceeded',
269+
params: {
270+
specialHermesFrameTypes,
271+
},
272+
});
273+
}
274+
262275
stackTraceSymbolicationFailed(stackTrace: string, line: string, reason: string): void {
263276
this.sendEvent({
264277
eventName: 'StackTraceSymbolicationFailed',
@@ -270,6 +283,21 @@ class RNPerfMetrics {
270283
});
271284
}
272285

286+
stackTraceFrameUrlResolutionSucceeded(): void {
287+
this.sendEvent({
288+
eventName: 'StackTraceFrameUrlResolutionSucceeded',
289+
});
290+
}
291+
292+
stackTraceFrameUrlResolutionFailed(uniqueUrls: string[]): void {
293+
this.sendEvent({
294+
eventName: 'StackTraceFrameUrlResolutionFailed',
295+
params: {
296+
uniqueUrls,
297+
},
298+
});
299+
}
300+
273301
panelShown(_panelName: string, _isLaunching?: boolean): void {
274302
// no-op
275303
// We only care about the "main" and "drawer" panels for now via panelShownInLocation(…)
@@ -434,6 +462,13 @@ export type PanelClosedEvent = Readonly<{
434462
}>,
435463
}>;
436464

465+
export type StackTraceSymbolicationSucceeded = Readonly<{
466+
eventName: 'StackTraceSymbolicationSucceeded',
467+
params: Readonly<{
468+
specialHermesFrameTypes: string[],
469+
}>,
470+
}>;
471+
437472
export type StackTraceSymbolicationFailed = Readonly<{
438473
eventName: 'StackTraceSymbolicationFailed',
439474
params: Readonly<{
@@ -443,10 +478,23 @@ export type StackTraceSymbolicationFailed = Readonly<{
443478
}>,
444479
}>;
445480

481+
export type StackTraceFrameUrlResolutionSucceeded = Readonly<{
482+
eventName: 'StackTraceFrameUrlResolutionSucceeded',
483+
}>;
484+
485+
export type StackTraceFrameUrlResolutionFailed = Readonly<{
486+
eventName: 'StackTraceFrameUrlResolutionFailed',
487+
params: Readonly<{
488+
uniqueUrls: string[],
489+
}>,
490+
}>;
491+
446492
export type ReactNativeChromeDevToolsEvent =
447493
EntrypointLoadingStartedEvent|EntrypointLoadingFinishedEvent|DebuggerReadyEvent|BrowserVisibilityChangeEvent|
448494
BrowserErrorEvent|RemoteDebuggingTerminatedEvent|DeveloperResourceLoadingStartedEvent|
449495
DeveloperResourceLoadingFinishedEvent|FuseboxSetClientMetadataStartedEvent|FuseboxSetClientMetadataFinishedEvent|
450-
MemoryPanelActionStartedEvent|MemoryPanelActionFinishedEvent|PanelShownEvent|PanelClosedEvent|StackTraceSymbolicationFailed;
496+
MemoryPanelActionStartedEvent|MemoryPanelActionFinishedEvent|PanelShownEvent|PanelClosedEvent|
497+
StackTraceSymbolicationSucceeded|StackTraceSymbolicationFailed|StackTraceFrameUrlResolutionSucceeded|
498+
StackTraceFrameUrlResolutionFailed;
451499

452500
export type DecoratedReactNativeChromeDevToolsEvent = CommonEventFields&ReactNativeChromeDevToolsEvent;

front_end/entrypoints/rn_fusebox/FuseboxExperimentsObserver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const UIStrings = {
2121
/**
2222
* @description Message for the "settings changed" banner shown when a reload is required for the Network panel.
2323
*/
24-
reloadRequiredForNetworkPanelMessage: 'Network panel is now available for dogfooding. Please reload to access it.',
24+
reloadRequiredForNetworkPanelMessage: 'The Network panel is now available for dogfooding. Please reload to access it.',
2525
} as const;
2626

2727
const str_ = i18n.i18n.registerUIStrings('entrypoints/rn_fusebox/FuseboxExperimentsObserver.ts', UIStrings);

front_end/panels/console/ConsoleViewMessage.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,21 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
18441844
});
18451845
}
18461846

1847+
if (Host.rnPerfMetrics.isEnabled()) {
1848+
const unresolvedScriptUrls = formattedResult
1849+
.querySelectorAll("[data-fallback-anchor='1']")
1850+
.values()
1851+
.map(element => element.getAttribute('title') || '')
1852+
.map(title => title.replace(/\:\d+(?:\:\d+)?$/, '')) // row and column e.g :11:11
1853+
.toArray();
1854+
if (unresolvedScriptUrls.length === 0) {
1855+
Host.rnPerfMetrics.stackTraceFrameUrlResolutionSucceeded();
1856+
} else {
1857+
const uniqueUrls = Array.from(new Set(unresolvedScriptUrls));
1858+
Host.rnPerfMetrics.stackTraceFrameUrlResolutionFailed(uniqueUrls);
1859+
}
1860+
}
1861+
18471862
return formattedResult;
18481863
}
18491864

front_end/panels/console/ErrorStackParser.ts

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,37 +21,57 @@ export interface ParsedErrorFrame {
2121
};
2222
}
2323

24-
export type SpecialHermesStackTraceFrameTypes = 'native' | 'address at' | 'empty url';
25-
26-
function getSpecialHermesStackTraceFrameType({
27-
url,
28-
}: {
29-
url: Platform.DevToolsPath.UrlString,
30-
}): SpecialHermesStackTraceFrameTypes | null {
31-
// functions implemented in c++.
32-
// TODO: these might be enhanced to include the C++ loc for the frame
33-
// so that a debugger could stitch together a hybrid cross-language call stack
24+
export type SpecialHermesStackTraceFrameTypes =
25+
// e.g "(native)"- Functions implemented on the native side.
26+
// TODO: Might be enhanced to include the native (C++/Java/etc) loc
27+
// for the frame so that a debugger could stitch together a
28+
// hybrid cross-language call stack
29+
'native' |
30+
// e.g "(eval:1:2)"- Seem to be reported when there's a
31+
// ReferenceError or TypeError during the initial bundle code execution.
32+
// TODO: Understand exactly where these originate from and what further work
33+
// should be done in regards to them
34+
'eval' |
35+
// e.g "(:3:4)"- Frames with empty url
36+
// TODO: Seems to be happening due to a bug that needs to be investigated
37+
// and produce an actual script URL instead
38+
'empty url' |
39+
// e.g "(address at InternalBytecode.js:5:6)"- Frames pointing to bytecode locations
40+
// TODO: Could be symbolicated and link to source files with the help of
41+
// a bytecode source maps once they are available.
42+
'address at' |
43+
// e.g " ... skipping 7 frames" - Frames collapsed in the middle of a stack trace
44+
// for very long stack traces
45+
'skipping x frames' ;
46+
47+
function getSpecialHermesFrameBasedOnURL(url: string): SpecialHermesStackTraceFrameTypes | null {
3448
if (url === 'native') {
3549
return 'native';
3650
}
3751

38-
// frames with empty url
39-
// TODO: these seem to be happening due to a bug that needs to be investigated
40-
// and produce an actual script URL instead
52+
if (url === 'eval') {
53+
return 'eval';
54+
}
55+
4156
if (url === '') {
4257
return 'empty url';
4358
}
4459

45-
// frames pointing to a bytecode locations
46-
// TODO: these could be symbolicated and link to source files with the help of
47-
// a bytecode source maps once they are available.
4860
if (url.startsWith?.('address at ')) {
4961
return 'address at';
5062
}
5163

5264
return null;
5365
}
5466

67+
function getSpecialHermesFrameBasedOnLine(line: string): SpecialHermesStackTraceFrameTypes | null {
68+
if (/^\s*... skipping \d+ frames$/.exec(line)) {
69+
return 'skipping x frames';
70+
}
71+
72+
return null;
73+
}
74+
5575
/**
5676
* Takes a V8 Error#stack string and extracts source position information.
5777
*
@@ -71,10 +91,24 @@ export function parseSourcePositionsFromErrorStack(
7191

7292
const lines = stack.split('\n');
7393
const linkInfos = [];
94+
const specialHermesFramesParsed = new Set<SpecialHermesStackTraceFrameTypes>();
95+
7496
for (const line of lines) {
7597
const match = /^\s*at\s(async\s)?/.exec(line);
7698
if (!match) {
7799
if (linkInfos.length && linkInfos[linkInfos.length - 1].isCallFrame) {
100+
const specialHermesFrameType = getSpecialHermesFrameBasedOnLine(line);
101+
if (specialHermesFrameType !== null) {
102+
specialHermesFramesParsed.add(specialHermesFrameType);
103+
if (!linkInfos[linkInfos.length - 1].link) {
104+
// Combine builtin frames.
105+
linkInfos[linkInfos.length - 1].line += `\n${line}`;
106+
} else {
107+
linkInfos.push({line, isCallFrame: false});
108+
}
109+
continue;
110+
}
111+
78112
Host.rnPerfMetrics.stackTraceSymbolicationFailed(stack, line, '"at (url)" not found');
79113
return null;
80114
}
@@ -110,7 +144,11 @@ export function parseSourcePositionsFromErrorStack(
110144

111145
const linkCandidate = line.substring(left, right);
112146
const splitResult = Common.ParsedURL.ParsedURL.splitLineAndColumn(linkCandidate);
113-
const specialHermesFrameType = getSpecialHermesStackTraceFrameType(splitResult);
147+
const specialHermesFrameType = getSpecialHermesFrameBasedOnURL(splitResult.url);
148+
if (specialHermesFrameType !== null) {
149+
specialHermesFramesParsed.add(specialHermesFrameType);
150+
}
151+
114152
if (splitResult.url === '<anonymous>' || specialHermesFrameType !== null) {
115153
if (linkInfos.length && linkInfos[linkInfos.length - 1].isCallFrame && !linkInfos[linkInfos.length - 1].link) {
116154
// Combine builtin frames.
@@ -142,6 +180,11 @@ export function parseSourcePositionsFromErrorStack(
142180
},
143181
});
144182
}
183+
184+
if (linkInfos?.length) {
185+
Host.rnPerfMetrics.stackTraceSymbolicationSucceeded(Array.from(specialHermesFramesParsed));
186+
}
187+
145188
return linkInfos;
146189
}
147190

front_end/panels/rn_welcome/RNWelcome.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,11 @@ export class RNWelcomeImpl extends UI.Widget.VBox implements
173173
</x-link>
174174
</div>
175175
${launchId ? html`
176-
<div class="rn-session-id">
176+
<div class="rn-session-id-message">
177177
${i18nString(UIStrings.sessionIdMessage)}
178-
<br/>
179-
${launchId}
178+
<div class="rn-session-id">
179+
${launchId}
180+
</div>
180181
</div>
181182
` : ''}
182183
${this.#reactNativeVersion !== null && this.#reactNativeVersion !== undefined ? html`

front_end/panels/rn_welcome/rnWelcome.css

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,12 @@
101101
border-right: 1px solid var(--sys-color-on-base-divider);
102102
}
103103

104-
.rn-session-id {
105-
display: flex;
106-
align-items: center;
104+
.rn-session-id-message {
105+
display: block;
107106
margin-top: 24px;
107+
}
108+
109+
.rn-session-id-message > .rn-session-id {
108110
user-select: all;
109111
}
110112

front_end/ui/legacy/components/utils/Linkifier.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
264264
const {columnNumber, className = ''} = linkifyURLOptions;
265265
if (sourceURL) {
266266
fallbackAnchor = Linkifier.linkifyURL(sourceURL, linkifyURLOptions);
267+
fallbackAnchor.dataset.fallbackAnchor = '1';
267268
}
268269
if (!target || target.isDisposed()) {
269270
return fallbackAnchor;

0 commit comments

Comments
 (0)