mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[DevTools] Add native events to the scheduling profiler (#21947)
This commit is contained in:
+47
-12
@@ -44,6 +44,7 @@ import {
|
||||
} from './view-base';
|
||||
import {
|
||||
FlamechartView,
|
||||
NativeEventsView,
|
||||
ReactEventsView,
|
||||
ReactMeasuresView,
|
||||
TimeAxisMarkersView,
|
||||
@@ -126,6 +127,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
|
||||
const surfaceRef = useRef(new Surface());
|
||||
const userTimingMarksViewRef = useRef(null);
|
||||
const nativeEventsViewRef = useRef(null);
|
||||
const reactEventsViewRef = useRef(null);
|
||||
const reactMeasuresViewRef = useRef(null);
|
||||
const flamechartViewRef = useRef(null);
|
||||
@@ -176,6 +178,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
topContentStack.addSubview(userTimingMarksView);
|
||||
}
|
||||
|
||||
const nativeEventsView = new NativeEventsView(surface, defaultFrame, data);
|
||||
nativeEventsViewRef.current = nativeEventsView;
|
||||
topContentStack.addSubview(nativeEventsView);
|
||||
|
||||
const reactEventsView = new ReactEventsView(surface, defaultFrame, data);
|
||||
reactEventsViewRef.current = reactEventsView;
|
||||
topContentStack.addSubview(reactEventsView);
|
||||
@@ -299,7 +305,24 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
if (!hoveredEvent || hoveredEvent.userTimingMark !== userTimingMark) {
|
||||
setHoveredEvent({
|
||||
userTimingMark,
|
||||
event: null,
|
||||
nativeEvent: null,
|
||||
reactEvent: null,
|
||||
flamechartStackFrame: null,
|
||||
measure: null,
|
||||
data,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const {current: nativeEventsView} = nativeEventsViewRef;
|
||||
if (nativeEventsView) {
|
||||
nativeEventsView.onHover = nativeEvent => {
|
||||
if (!hoveredEvent || hoveredEvent.nativeEvent !== nativeEvent) {
|
||||
setHoveredEvent({
|
||||
userTimingMark: null,
|
||||
nativeEvent,
|
||||
reactEvent: null,
|
||||
flamechartStackFrame: null,
|
||||
measure: null,
|
||||
data,
|
||||
@@ -310,11 +333,12 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
|
||||
const {current: reactEventsView} = reactEventsViewRef;
|
||||
if (reactEventsView) {
|
||||
reactEventsView.onHover = event => {
|
||||
if (!hoveredEvent || hoveredEvent.event !== event) {
|
||||
reactEventsView.onHover = reactEvent => {
|
||||
if (!hoveredEvent || hoveredEvent.reactEvent !== reactEvent) {
|
||||
setHoveredEvent({
|
||||
userTimingMark: null,
|
||||
event,
|
||||
nativeEvent: null,
|
||||
reactEvent,
|
||||
flamechartStackFrame: null,
|
||||
measure: null,
|
||||
data,
|
||||
@@ -329,7 +353,8 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
if (!hoveredEvent || hoveredEvent.measure !== measure) {
|
||||
setHoveredEvent({
|
||||
userTimingMark: null,
|
||||
event: null,
|
||||
nativeEvent: null,
|
||||
reactEvent: null,
|
||||
flamechartStackFrame: null,
|
||||
measure,
|
||||
data,
|
||||
@@ -347,7 +372,8 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
) {
|
||||
setHoveredEvent({
|
||||
userTimingMark: null,
|
||||
event: null,
|
||||
nativeEvent: null,
|
||||
reactEvent: null,
|
||||
flamechartStackFrame,
|
||||
measure: null,
|
||||
data,
|
||||
@@ -368,9 +394,18 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const {current: nativeEventsView} = nativeEventsViewRef;
|
||||
if (nativeEventsView) {
|
||||
nativeEventsView.setHoveredEvent(
|
||||
hoveredEvent ? hoveredEvent.nativeEvent : null,
|
||||
);
|
||||
}
|
||||
|
||||
const {current: reactEventsView} = reactEventsViewRef;
|
||||
if (reactEventsView) {
|
||||
reactEventsView.setHoveredEvent(hoveredEvent ? hoveredEvent.event : null);
|
||||
reactEventsView.setHoveredEvent(
|
||||
hoveredEvent ? hoveredEvent.reactEvent : null,
|
||||
);
|
||||
}
|
||||
|
||||
const {current: reactMeasuresView} = reactMeasuresViewRef;
|
||||
@@ -402,22 +437,22 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
event,
|
||||
reactEvent,
|
||||
flamechartStackFrame,
|
||||
measure,
|
||||
} = contextData.hoveredEvent;
|
||||
return (
|
||||
<Fragment>
|
||||
{event !== null && (
|
||||
{reactEvent !== null && (
|
||||
<ContextMenuItem
|
||||
onClick={() => copy(event.componentName)}
|
||||
onClick={() => copy(reactEvent.componentName)}
|
||||
title="Copy component name">
|
||||
Copy component name
|
||||
</ContextMenuItem>
|
||||
)}
|
||||
{event !== null && event.componentStack && (
|
||||
{reactEvent !== null && reactEvent.componentStack && (
|
||||
<ContextMenuItem
|
||||
onClick={() => copy(event.componentStack)}
|
||||
onClick={() => copy(reactEvent.componentStack)}
|
||||
title="Copy component stack">
|
||||
Copy component stack
|
||||
</ContextMenuItem>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
.DetailsGridLabel {
|
||||
color: var(--color-dim);
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.DetailsGridURL {
|
||||
@@ -45,7 +46,7 @@
|
||||
.ComponentName {
|
||||
font-weight: bold;
|
||||
word-break: break-word;
|
||||
margin-right: 0.4rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.ComponentStack {
|
||||
|
||||
+49
-12
@@ -10,6 +10,7 @@
|
||||
import type {Point} from './view-base';
|
||||
import type {
|
||||
FlamechartStackFrame,
|
||||
NativeEvent,
|
||||
ReactEvent,
|
||||
ReactHoverContextInfo,
|
||||
ReactMeasure,
|
||||
@@ -47,8 +48,8 @@ function trimmedString(string: string, length: number): string {
|
||||
return string;
|
||||
}
|
||||
|
||||
function getReactEventLabel(type): string | null {
|
||||
switch (type) {
|
||||
function getReactEventLabel(event: ReactEvent): string | null {
|
||||
switch (event.type) {
|
||||
case 'schedule-render':
|
||||
return 'render scheduled';
|
||||
case 'schedule-state-update':
|
||||
@@ -111,10 +112,22 @@ export default function EventTooltip({data, hoveredEvent, origin}: Props) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {event, measure, flamechartStackFrame, userTimingMark} = hoveredEvent;
|
||||
const {
|
||||
nativeEvent,
|
||||
reactEvent,
|
||||
measure,
|
||||
flamechartStackFrame,
|
||||
userTimingMark,
|
||||
} = hoveredEvent;
|
||||
|
||||
if (event !== null) {
|
||||
return <TooltipReactEvent event={event} tooltipRef={tooltipRef} />;
|
||||
if (nativeEvent !== null) {
|
||||
return (
|
||||
<TooltipNativeEvent nativeEvent={nativeEvent} tooltipRef={tooltipRef} />
|
||||
);
|
||||
} else if (reactEvent !== null) {
|
||||
return (
|
||||
<TooltipReactEvent reactEvent={reactEvent} tooltipRef={tooltipRef} />
|
||||
);
|
||||
} else if (measure !== null) {
|
||||
return (
|
||||
<TooltipReactMeasure
|
||||
@@ -189,23 +202,47 @@ const TooltipFlamechartNode = ({
|
||||
);
|
||||
};
|
||||
|
||||
const TooltipReactEvent = ({
|
||||
event,
|
||||
const TooltipNativeEvent = ({
|
||||
nativeEvent,
|
||||
tooltipRef,
|
||||
}: {
|
||||
event: ReactEvent,
|
||||
nativeEvent: NativeEvent,
|
||||
tooltipRef: Return<typeof useRef>,
|
||||
}) => {
|
||||
const label = getReactEventLabel(event.type);
|
||||
const color = getReactEventColor(event);
|
||||
const {duration, timestamp, type} = nativeEvent;
|
||||
|
||||
return (
|
||||
<div className={styles.Tooltip} ref={tooltipRef}>
|
||||
<span className={styles.ComponentName}>{trimmedString(type, 768)}</span>
|
||||
event
|
||||
<div className={styles.Divider} />
|
||||
<div className={styles.DetailsGrid}>
|
||||
<div className={styles.DetailsGridLabel}>Timestamp:</div>
|
||||
<div>{formatTimestamp(timestamp)}</div>
|
||||
<div className={styles.DetailsGridLabel}>Duration:</div>
|
||||
<div>{formatDuration(duration)}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TooltipReactEvent = ({
|
||||
reactEvent,
|
||||
tooltipRef,
|
||||
}: {
|
||||
reactEvent: ReactEvent,
|
||||
tooltipRef: Return<typeof useRef>,
|
||||
}) => {
|
||||
const label = getReactEventLabel(reactEvent);
|
||||
const color = getReactEventColor(reactEvent);
|
||||
if (!label || !color) {
|
||||
if (__DEV__) {
|
||||
console.warn('Unexpected event type "%s"', event.type);
|
||||
console.warn('Unexpected reactEvent type "%s"', reactEvent.type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const {componentName, componentStack, timestamp} = event;
|
||||
const {componentName, componentStack, timestamp} = reactEvent;
|
||||
|
||||
return (
|
||||
<div className={styles.Tooltip} ref={tooltipRef}>
|
||||
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {NativeEvent, ReactProfilerData} from '../types';
|
||||
import type {Interaction, MouseMoveInteraction, Rect, Size} from '../view-base';
|
||||
|
||||
import {
|
||||
positioningScaleFactor,
|
||||
timestampToPosition,
|
||||
positionToTimestamp,
|
||||
} from './utils/positioning';
|
||||
import {
|
||||
View,
|
||||
Surface,
|
||||
rectContainsPoint,
|
||||
rectIntersectsRect,
|
||||
intersectionOfRects,
|
||||
} from '../view-base';
|
||||
import {
|
||||
COLORS,
|
||||
EVENT_ROW_PADDING,
|
||||
EVENT_DIAMETER,
|
||||
BORDER_SIZE,
|
||||
} from './constants';
|
||||
|
||||
const EVENT_ROW_HEIGHT_FIXED =
|
||||
EVENT_ROW_PADDING + EVENT_DIAMETER + EVENT_ROW_PADDING;
|
||||
|
||||
export class NativeEventsView extends View {
|
||||
_profilerData: ReactProfilerData;
|
||||
_intrinsicSize: Size;
|
||||
|
||||
_hoveredEvent: NativeEvent | null = null;
|
||||
onHover: ((event: NativeEvent | null) => void) | null = null;
|
||||
|
||||
constructor(surface: Surface, frame: Rect, profilerData: ReactProfilerData) {
|
||||
super(surface, frame);
|
||||
this._profilerData = profilerData;
|
||||
|
||||
this._intrinsicSize = {
|
||||
width: this._profilerData.duration,
|
||||
height: EVENT_ROW_HEIGHT_FIXED,
|
||||
};
|
||||
}
|
||||
|
||||
desiredSize() {
|
||||
return this._intrinsicSize;
|
||||
}
|
||||
|
||||
setHoveredEvent(hoveredEvent: NativeEvent | null) {
|
||||
if (this._hoveredEvent === hoveredEvent) {
|
||||
return;
|
||||
}
|
||||
this._hoveredEvent = hoveredEvent;
|
||||
this.setNeedsDisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a single `NativeEvent` as a circle in the canvas.
|
||||
*/
|
||||
_drawSingleNativeEvent(
|
||||
context: CanvasRenderingContext2D,
|
||||
rect: Rect,
|
||||
event: NativeEvent,
|
||||
baseY: number,
|
||||
scaleFactor: number,
|
||||
showHoverHighlight: boolean,
|
||||
) {
|
||||
const {frame} = this;
|
||||
const {duration, timestamp} = event;
|
||||
|
||||
const xStart = timestampToPosition(timestamp, scaleFactor, frame);
|
||||
const xStop = timestampToPosition(timestamp + duration, scaleFactor, frame);
|
||||
const eventRect: Rect = {
|
||||
origin: {
|
||||
x: xStart,
|
||||
y: baseY,
|
||||
},
|
||||
size: {width: xStop - xStart, height: EVENT_DIAMETER},
|
||||
};
|
||||
if (!rectIntersectsRect(eventRect, rect)) {
|
||||
return; // Not in view
|
||||
}
|
||||
|
||||
const fillStyle = showHoverHighlight
|
||||
? COLORS.NATIVE_EVENT_HOVER
|
||||
: COLORS.NATIVE_EVENT;
|
||||
|
||||
const drawableRect = intersectionOfRects(eventRect, rect);
|
||||
context.beginPath();
|
||||
context.fillStyle = fillStyle;
|
||||
context.fillRect(
|
||||
drawableRect.origin.x,
|
||||
drawableRect.origin.y,
|
||||
drawableRect.size.width,
|
||||
drawableRect.size.height,
|
||||
);
|
||||
}
|
||||
|
||||
draw(context: CanvasRenderingContext2D) {
|
||||
const {
|
||||
frame,
|
||||
_profilerData: {nativeEvents},
|
||||
_hoveredEvent,
|
||||
visibleArea,
|
||||
} = this;
|
||||
|
||||
context.fillStyle = COLORS.BACKGROUND;
|
||||
context.fillRect(
|
||||
visibleArea.origin.x,
|
||||
visibleArea.origin.y,
|
||||
visibleArea.size.width,
|
||||
visibleArea.size.height,
|
||||
);
|
||||
|
||||
// Draw events
|
||||
const baseY = frame.origin.y + EVENT_ROW_PADDING;
|
||||
const scaleFactor = positioningScaleFactor(
|
||||
this._intrinsicSize.width,
|
||||
frame,
|
||||
);
|
||||
|
||||
nativeEvents.forEach(event => {
|
||||
if (event === _hoveredEvent) {
|
||||
// Draw the highlighted items on top so they stand out.
|
||||
// This is helpful if there are multiple (overlapping) items close to each other.
|
||||
this._drawSingleNativeEvent(
|
||||
context,
|
||||
visibleArea,
|
||||
event,
|
||||
baseY,
|
||||
scaleFactor,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
this._drawSingleNativeEvent(
|
||||
context,
|
||||
visibleArea,
|
||||
event,
|
||||
baseY,
|
||||
scaleFactor,
|
||||
false,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Render bottom border.
|
||||
// Propose border rect, check if intersects with `rect`, draw intersection.
|
||||
const borderFrame: Rect = {
|
||||
origin: {
|
||||
x: frame.origin.x,
|
||||
y: frame.origin.y + EVENT_ROW_HEIGHT_FIXED - BORDER_SIZE,
|
||||
},
|
||||
size: {
|
||||
width: frame.size.width,
|
||||
height: BORDER_SIZE,
|
||||
},
|
||||
};
|
||||
if (rectIntersectsRect(borderFrame, visibleArea)) {
|
||||
const borderDrawableRect = intersectionOfRects(borderFrame, visibleArea);
|
||||
context.fillStyle = COLORS.PRIORITY_BORDER;
|
||||
context.fillRect(
|
||||
borderDrawableRect.origin.x,
|
||||
borderDrawableRect.origin.y,
|
||||
borderDrawableRect.size.width,
|
||||
borderDrawableRect.size.height,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_handleMouseMove(interaction: MouseMoveInteraction) {
|
||||
const {frame, _intrinsicSize, onHover, visibleArea} = this;
|
||||
if (!onHover) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {location} = interaction.payload;
|
||||
if (!rectContainsPoint(location, visibleArea)) {
|
||||
onHover(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const {nativeEvents} = this._profilerData;
|
||||
|
||||
const scaleFactor = positioningScaleFactor(_intrinsicSize.width, frame);
|
||||
const hoverTimestamp = positionToTimestamp(location.x, scaleFactor, frame);
|
||||
|
||||
// Find the event being hovered over.
|
||||
//
|
||||
// Because data ranges may overlap, we want to find the last intersecting item.
|
||||
// This will always be the one on "top" (the one the user is hovering over).
|
||||
for (let index = nativeEvents.length - 1; index >= 0; index--) {
|
||||
const nativeEvent = nativeEvents[index];
|
||||
const {duration, timestamp} = nativeEvent;
|
||||
|
||||
if (
|
||||
hoverTimestamp >= timestamp &&
|
||||
hoverTimestamp <= timestamp + duration
|
||||
) {
|
||||
onHover(nativeEvent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onHover(null);
|
||||
}
|
||||
|
||||
handleInteraction(interaction: Interaction) {
|
||||
switch (interaction.type) {
|
||||
case 'mousemove':
|
||||
this._handleMouseMove(interaction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -100,6 +100,8 @@ export class ReactEventsView extends View {
|
||||
let fillStyle = null;
|
||||
|
||||
switch (type) {
|
||||
case 'native-event':
|
||||
return;
|
||||
case 'schedule-render':
|
||||
case 'schedule-state-update':
|
||||
case 'schedule-force-update':
|
||||
@@ -140,7 +142,7 @@ export class ReactEventsView extends View {
|
||||
draw(context: CanvasRenderingContext2D) {
|
||||
const {
|
||||
frame,
|
||||
_profilerData: {events},
|
||||
_profilerData: {reactEvents},
|
||||
_hoveredEvent,
|
||||
visibleArea,
|
||||
} = this;
|
||||
@@ -162,7 +164,7 @@ export class ReactEventsView extends View {
|
||||
|
||||
const highlightedEvents: ReactEvent[] = [];
|
||||
|
||||
events.forEach(event => {
|
||||
reactEvents.forEach(event => {
|
||||
if (
|
||||
event === _hoveredEvent ||
|
||||
(_hoveredEvent &&
|
||||
@@ -236,7 +238,7 @@ export class ReactEventsView extends View {
|
||||
}
|
||||
|
||||
const {
|
||||
_profilerData: {events},
|
||||
_profilerData: {reactEvents},
|
||||
} = this;
|
||||
const scaleFactor = positioningScaleFactor(
|
||||
this._intrinsicSize.width,
|
||||
@@ -250,8 +252,8 @@ export class ReactEventsView extends View {
|
||||
|
||||
// Because data ranges may overlap, we want to find the last intersecting item.
|
||||
// This will always be the one on "top" (the one the user is hovering over).
|
||||
for (let index = events.length - 1; index >= 0; index--) {
|
||||
const event = events[index];
|
||||
for (let index = reactEvents.length - 1; index >= 0; index--) {
|
||||
const event = reactEvents[index];
|
||||
const {timestamp} = event;
|
||||
|
||||
if (
|
||||
|
||||
+12
-4
@@ -44,10 +44,12 @@ export const FLAMECHART_TEXT_PADDING = 3;
|
||||
// TODO Replace this with "export let" vars
|
||||
export let COLORS = {
|
||||
BACKGROUND: '',
|
||||
FLAME_GRAPH_LABEL: '',
|
||||
NATIVE_EVENT: '',
|
||||
NATIVE_EVENT_HOVER: '',
|
||||
PRIORITY_BACKGROUND: '',
|
||||
PRIORITY_BORDER: '',
|
||||
PRIORITY_LABEL: '',
|
||||
FLAME_GRAPH_LABEL: '',
|
||||
USER_TIMING: '',
|
||||
USER_TIMING_HOVER: '',
|
||||
REACT_IDLE: '',
|
||||
@@ -81,6 +83,15 @@ export function updateColorsToMatchTheme(): void {
|
||||
|
||||
COLORS = {
|
||||
BACKGROUND: computedStyle.getPropertyValue('--color-background'),
|
||||
FLAME_GRAPH_LABEL: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-flame-graph-label',
|
||||
),
|
||||
NATIVE_EVENT: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-native-event',
|
||||
),
|
||||
NATIVE_EVENT_HOVER: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-native-event-hover',
|
||||
),
|
||||
PRIORITY_BACKGROUND: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-priority-background',
|
||||
),
|
||||
@@ -88,9 +99,6 @@ export function updateColorsToMatchTheme(): void {
|
||||
'--color-scheduling-profiler-priority-border',
|
||||
),
|
||||
PRIORITY_LABEL: computedStyle.getPropertyValue('--color-text'),
|
||||
FLAME_GRAPH_LABEL: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-flame-graph-label',
|
||||
),
|
||||
USER_TIMING: computedStyle.getPropertyValue(
|
||||
'--color-scheduling-profiler-user-timing',
|
||||
),
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
export * from './FlamechartView';
|
||||
export * from './NativeEventsView';
|
||||
export * from './ReactEventsView';
|
||||
export * from './ReactMeasuresView';
|
||||
export * from './TimeAxisMarkersView';
|
||||
|
||||
+41
-37
@@ -204,10 +204,11 @@ describe(preprocessData, () => {
|
||||
|
||||
expect(preprocessData([cpuProfilerSample, randomSample])).toStrictEqual({
|
||||
duration: 0.002,
|
||||
events: [],
|
||||
flamechart: [],
|
||||
measures: [],
|
||||
nativeEvents: [],
|
||||
otherUserTimingMarks: [],
|
||||
reactEvents: [],
|
||||
startTime: 1,
|
||||
});
|
||||
});
|
||||
@@ -258,15 +259,6 @@ describe(preprocessData, () => {
|
||||
]),
|
||||
).toStrictEqual({
|
||||
duration: 0.008,
|
||||
events: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: [],
|
||||
lanes: [9],
|
||||
timestamp: 0.002,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
],
|
||||
flamechart: [],
|
||||
measures: [
|
||||
{
|
||||
@@ -306,7 +298,17 @@ describe(preprocessData, () => {
|
||||
type: 'layout-effects',
|
||||
},
|
||||
],
|
||||
nativeEvents: [],
|
||||
otherUserTimingMarks: [],
|
||||
reactEvents: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: [],
|
||||
lanes: [9],
|
||||
timestamp: 0.002,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
],
|
||||
startTime: 1,
|
||||
});
|
||||
});
|
||||
@@ -320,15 +322,6 @@ describe(preprocessData, () => {
|
||||
const userTimingData = createUserTimingData(clearedMarks);
|
||||
expect(preprocessData(userTimingData)).toStrictEqual({
|
||||
duration: 0.011,
|
||||
events: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: ['Sync'],
|
||||
lanes: [0],
|
||||
timestamp: 0.005,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
],
|
||||
flamechart: [],
|
||||
measures: [
|
||||
{
|
||||
@@ -368,6 +361,7 @@ describe(preprocessData, () => {
|
||||
type: 'layout-effects',
|
||||
},
|
||||
],
|
||||
nativeEvents: [],
|
||||
otherUserTimingMarks: [
|
||||
{
|
||||
name: '__v3',
|
||||
@@ -378,6 +372,15 @@ describe(preprocessData, () => {
|
||||
timestamp: 0.004,
|
||||
},
|
||||
],
|
||||
reactEvents: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: ['Sync'],
|
||||
lanes: [0],
|
||||
timestamp: 0.005,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
],
|
||||
startTime: 1,
|
||||
});
|
||||
});
|
||||
@@ -400,24 +403,6 @@ describe(preprocessData, () => {
|
||||
const userTimingData = createUserTimingData(clearedMarks);
|
||||
expect(preprocessData(userTimingData)).toStrictEqual({
|
||||
duration: 0.022,
|
||||
events: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: ['Default'],
|
||||
lanes: [4],
|
||||
timestamp: 0.005,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
{
|
||||
componentName: 'App',
|
||||
componentStack: '',
|
||||
isCascading: false,
|
||||
laneLabels: ['Default'],
|
||||
lanes: [4],
|
||||
timestamp: 0.013,
|
||||
type: 'schedule-state-update',
|
||||
},
|
||||
],
|
||||
flamechart: [],
|
||||
measures: [
|
||||
{
|
||||
@@ -511,6 +496,7 @@ describe(preprocessData, () => {
|
||||
type: 'passive-effects',
|
||||
},
|
||||
],
|
||||
nativeEvents: [],
|
||||
otherUserTimingMarks: [
|
||||
{
|
||||
name: '__v3',
|
||||
@@ -521,6 +507,24 @@ describe(preprocessData, () => {
|
||||
timestamp: 0.004,
|
||||
},
|
||||
],
|
||||
reactEvents: [
|
||||
{
|
||||
componentStack: '',
|
||||
laneLabels: ['Default'],
|
||||
lanes: [4],
|
||||
timestamp: 0.005,
|
||||
type: 'schedule-render',
|
||||
},
|
||||
{
|
||||
componentName: 'App',
|
||||
componentStack: '',
|
||||
isCascading: false,
|
||||
laneLabels: ['Default'],
|
||||
lanes: [4],
|
||||
timestamp: 0.013,
|
||||
type: 'schedule-state-update',
|
||||
},
|
||||
],
|
||||
startTime: 1,
|
||||
});
|
||||
});
|
||||
|
||||
+262
-233
@@ -161,247 +161,275 @@ function processTimelineEvent(
|
||||
/** Intermediate processor state. May be mutated. */
|
||||
state: ProcessorState,
|
||||
) {
|
||||
const {cat, name, ts, ph} = event;
|
||||
if (cat !== 'blink.user_timing') {
|
||||
return;
|
||||
}
|
||||
const {args, cat, name, ts, ph} = event;
|
||||
switch (cat) {
|
||||
case 'devtools.timeline':
|
||||
if (name === 'EventDispatch') {
|
||||
const type = args.data.type;
|
||||
|
||||
const startTime = (ts - currentProfilerData.startTime) / 1000;
|
||||
if (type.startsWith('react-')) {
|
||||
const stackTrace = args.data.stackTrace;
|
||||
if (stackTrace) {
|
||||
const topFrame = stackTrace[stackTrace.length - 1];
|
||||
if (topFrame.url.includes('node_modules/react-dom')) {
|
||||
// Filter out fake React events dispatched by invokeGuardedCallbackDev.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// React Events - schedule
|
||||
if (name.startsWith('--schedule-render-')) {
|
||||
const [laneBitmaskString, laneLabels, ...splitComponentStack] = name
|
||||
.substr(18)
|
||||
.split('-');
|
||||
currentProfilerData.events.push({
|
||||
type: 'schedule-render',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--schedule-forced-update-')) {
|
||||
const [
|
||||
laneBitmaskString,
|
||||
laneLabels,
|
||||
componentName,
|
||||
...splitComponentStack
|
||||
] = name.substr(25).split('-');
|
||||
const isCascading = !!state.measureStack.find(
|
||||
({type}) => type === 'commit',
|
||||
);
|
||||
currentProfilerData.events.push({
|
||||
type: 'schedule-force-update',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
isCascading,
|
||||
});
|
||||
} else if (name.startsWith('--schedule-state-update-')) {
|
||||
const [
|
||||
laneBitmaskString,
|
||||
laneLabels,
|
||||
componentName,
|
||||
...splitComponentStack
|
||||
] = name.substr(24).split('-');
|
||||
const isCascading = !!state.measureStack.find(
|
||||
({type}) => type === 'commit',
|
||||
);
|
||||
currentProfilerData.events.push({
|
||||
type: 'schedule-state-update',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
isCascading,
|
||||
});
|
||||
} // eslint-disable-line brace-style
|
||||
const startTime = (ts - currentProfilerData.startTime) / 1000;
|
||||
const duration = event.dur / 1000;
|
||||
|
||||
// React Events - suspense
|
||||
else if (name.startsWith('--suspense-suspend-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(19)
|
||||
.split('-');
|
||||
currentProfilerData.events.push({
|
||||
type: 'suspense-suspend',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--suspense-resolved-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(20)
|
||||
.split('-');
|
||||
currentProfilerData.events.push({
|
||||
type: 'suspense-resolved',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--suspense-rejected-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(20)
|
||||
.split('-');
|
||||
currentProfilerData.events.push({
|
||||
type: 'suspense-rejected',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} // eslint-disable-line brace-style
|
||||
// TODO (scheduling profiler) Should we filter out certain event types?
|
||||
currentProfilerData.nativeEvents.push({
|
||||
duration,
|
||||
timestamp: startTime,
|
||||
type,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'blink.user_timing':
|
||||
const startTime = (ts - currentProfilerData.startTime) / 1000;
|
||||
|
||||
// React Measures - render
|
||||
else if (name.startsWith('--render-start-')) {
|
||||
if (state.nextRenderShouldGenerateNewBatchID) {
|
||||
state.nextRenderShouldGenerateNewBatchID = false;
|
||||
state.batchUID = ((state.uidCounter++: any): BatchUID);
|
||||
}
|
||||
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
throwIfIncomplete('render', state.measureStack);
|
||||
if (getLastType(state.measureStack) !== 'render-idle') {
|
||||
markWorkStarted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
}
|
||||
markWorkStarted(
|
||||
'render',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (
|
||||
name.startsWith('--render-stop') ||
|
||||
name.startsWith('--render-yield')
|
||||
) {
|
||||
markWorkCompleted(
|
||||
'render',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} else if (name.startsWith('--render-cancel')) {
|
||||
state.nextRenderShouldGenerateNewBatchID = true;
|
||||
markWorkCompleted(
|
||||
'render',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
markWorkCompleted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
// React Events - schedule
|
||||
if (name.startsWith('--schedule-render-')) {
|
||||
const [
|
||||
laneBitmaskString,
|
||||
laneLabels,
|
||||
...splitComponentStack
|
||||
] = name.substr(18).split('-');
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'schedule-render',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--schedule-forced-update-')) {
|
||||
const [
|
||||
laneBitmaskString,
|
||||
laneLabels,
|
||||
componentName,
|
||||
...splitComponentStack
|
||||
] = name.substr(25).split('-');
|
||||
const isCascading = !!state.measureStack.find(
|
||||
({type}) => type === 'commit',
|
||||
);
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'schedule-force-update',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
isCascading,
|
||||
});
|
||||
} else if (name.startsWith('--schedule-state-update-')) {
|
||||
const [
|
||||
laneBitmaskString,
|
||||
laneLabels,
|
||||
componentName,
|
||||
...splitComponentStack
|
||||
] = name.substr(24).split('-');
|
||||
const isCascading = !!state.measureStack.find(
|
||||
({type}) => type === 'commit',
|
||||
);
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'schedule-state-update',
|
||||
lanes: getLanesFromTransportDecimalBitmask(laneBitmaskString),
|
||||
laneLabels: laneLabels ? laneLabels.split(',') : [],
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
isCascading,
|
||||
});
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// React Measures - commits
|
||||
else if (name.startsWith('--commit-start-')) {
|
||||
state.nextRenderShouldGenerateNewBatchID = true;
|
||||
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'commit',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--commit-stop')) {
|
||||
markWorkCompleted(
|
||||
'commit',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
markWorkCompleted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
// React Events - suspense
|
||||
else if (name.startsWith('--suspense-suspend-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(19)
|
||||
.split('-');
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'suspense-suspend',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--suspense-resolved-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(20)
|
||||
.split('-');
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'suspense-resolved',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (name.startsWith('--suspense-rejected-')) {
|
||||
const [id, componentName, ...splitComponentStack] = name
|
||||
.substr(20)
|
||||
.split('-');
|
||||
currentProfilerData.reactEvents.push({
|
||||
type: 'suspense-rejected',
|
||||
id,
|
||||
componentName,
|
||||
componentStack: splitComponentStack.join('-'),
|
||||
timestamp: startTime,
|
||||
});
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// React Measures - layout effects
|
||||
else if (name.startsWith('--layout-effects-start-')) {
|
||||
const [laneBitmaskString, laneLabels] = name.substr(23).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'layout-effects',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--layout-effects-stop')) {
|
||||
markWorkCompleted(
|
||||
'layout-effects',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
// React Measures - render
|
||||
else if (name.startsWith('--render-start-')) {
|
||||
if (state.nextRenderShouldGenerateNewBatchID) {
|
||||
state.nextRenderShouldGenerateNewBatchID = false;
|
||||
state.batchUID = ((state.uidCounter++: any): BatchUID);
|
||||
}
|
||||
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
throwIfIncomplete('render', state.measureStack);
|
||||
if (getLastType(state.measureStack) !== 'render-idle') {
|
||||
markWorkStarted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
}
|
||||
markWorkStarted(
|
||||
'render',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (
|
||||
name.startsWith('--render-stop') ||
|
||||
name.startsWith('--render-yield')
|
||||
) {
|
||||
markWorkCompleted(
|
||||
'render',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} else if (name.startsWith('--render-cancel')) {
|
||||
state.nextRenderShouldGenerateNewBatchID = true;
|
||||
markWorkCompleted(
|
||||
'render',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
markWorkCompleted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// React Measures - passive effects
|
||||
else if (name.startsWith('--passive-effects-start-')) {
|
||||
const [laneBitmaskString, laneLabels] = name.substr(24).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'passive-effects',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--passive-effects-stop')) {
|
||||
markWorkCompleted(
|
||||
'passive-effects',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
// React Measures - commits
|
||||
else if (name.startsWith('--commit-start-')) {
|
||||
state.nextRenderShouldGenerateNewBatchID = true;
|
||||
const [laneBitmaskString, laneLabels] = name.substr(15).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'commit',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--commit-stop')) {
|
||||
markWorkCompleted(
|
||||
'commit',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
markWorkCompleted(
|
||||
'render-idle',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// Other user timing marks/measures
|
||||
else if (ph === 'R' || ph === 'n') {
|
||||
// User Timing mark
|
||||
currentProfilerData.otherUserTimingMarks.push({
|
||||
name,
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (ph === 'b') {
|
||||
// TODO: Begin user timing measure
|
||||
} else if (ph === 'e') {
|
||||
// TODO: End user timing measure
|
||||
} else if (ph === 'i' || ph === 'I') {
|
||||
// Instant events.
|
||||
// Note that the capital "I" is a deprecated value that exists in Chrome Canary traces.
|
||||
} // eslint-disable-line brace-style
|
||||
// React Measures - layout effects
|
||||
else if (name.startsWith('--layout-effects-start-')) {
|
||||
const [laneBitmaskString, laneLabels] = name.substr(23).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'layout-effects',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--layout-effects-stop')) {
|
||||
markWorkCompleted(
|
||||
'layout-effects',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// Unrecognized event
|
||||
else {
|
||||
throw new InvalidProfileError(
|
||||
`Unrecognized event ${JSON.stringify(
|
||||
event,
|
||||
)}! This is likely a bug in this profiler tool.`,
|
||||
);
|
||||
// React Measures - passive effects
|
||||
else if (name.startsWith('--passive-effects-start-')) {
|
||||
const [laneBitmaskString, laneLabels] = name.substr(24).split('-');
|
||||
const lanes = getLanesFromTransportDecimalBitmask(laneBitmaskString);
|
||||
markWorkStarted(
|
||||
'passive-effects',
|
||||
startTime,
|
||||
lanes,
|
||||
laneLabels ? laneLabels.split(',') : [],
|
||||
currentProfilerData,
|
||||
state,
|
||||
);
|
||||
} else if (name.startsWith('--passive-effects-stop')) {
|
||||
markWorkCompleted(
|
||||
'passive-effects',
|
||||
startTime,
|
||||
currentProfilerData,
|
||||
state.measureStack,
|
||||
);
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// Other user timing marks/measures
|
||||
else if (ph === 'R' || ph === 'n') {
|
||||
// User Timing mark
|
||||
currentProfilerData.otherUserTimingMarks.push({
|
||||
name,
|
||||
timestamp: startTime,
|
||||
});
|
||||
} else if (ph === 'b') {
|
||||
// TODO: Begin user timing measure
|
||||
} else if (ph === 'e') {
|
||||
// TODO: End user timing measure
|
||||
} else if (ph === 'i' || ph === 'I') {
|
||||
// Instant events.
|
||||
// Note that the capital "I" is a deprecated value that exists in Chrome Canary traces.
|
||||
} // eslint-disable-line brace-style
|
||||
|
||||
// Unrecognized event
|
||||
else {
|
||||
throw new InvalidProfileError(
|
||||
`Unrecognized event ${JSON.stringify(
|
||||
event,
|
||||
)}! This is likely a bug in this profiler tool.`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +475,8 @@ export default function preprocessData(
|
||||
const profilerData: ReactProfilerData = {
|
||||
startTime: 0,
|
||||
duration: 0,
|
||||
events: [],
|
||||
nativeEvents: [],
|
||||
reactEvents: [],
|
||||
measures: [],
|
||||
flamechart,
|
||||
otherUserTimingMarks: [],
|
||||
|
||||
+10
-2
@@ -21,6 +21,12 @@ export type Milliseconds = number;
|
||||
|
||||
export type ReactLane = number;
|
||||
|
||||
export type NativeEvent = {|
|
||||
+duration: Milliseconds,
|
||||
+timestamp: Milliseconds,
|
||||
+type: string,
|
||||
|};
|
||||
|
||||
type BaseReactEvent = {|
|
||||
+componentName?: string,
|
||||
+componentStack?: string,
|
||||
@@ -122,14 +128,16 @@ export type Flamechart = FlamechartStackLayer[];
|
||||
export type ReactProfilerData = {|
|
||||
startTime: number,
|
||||
duration: number,
|
||||
events: ReactEvent[],
|
||||
nativeEvents: NativeEvent[],
|
||||
reactEvents: ReactEvent[],
|
||||
measures: ReactMeasure[],
|
||||
flamechart: Flamechart,
|
||||
otherUserTimingMarks: UserTimingMark[],
|
||||
|};
|
||||
|
||||
export type ReactHoverContextInfo = {|
|
||||
event: ReactEvent | null,
|
||||
nativeEvent: NativeEvent | null,
|
||||
reactEvent: ReactEvent | null,
|
||||
measure: ReactMeasure | null,
|
||||
data: $ReadOnly<ReactProfilerData> | null,
|
||||
flamechartStackFrame: FlamechartStackFrame | null,
|
||||
|
||||
+10
@@ -421,6 +421,16 @@ export function updateThemeVariables(
|
||||
'color-scheduling-profiler-flame-graph-label',
|
||||
documentElements,
|
||||
);
|
||||
updateStyleHelper(
|
||||
theme,
|
||||
'color-scheduling-profiler-native-event',
|
||||
documentElements,
|
||||
);
|
||||
updateStyleHelper(
|
||||
theme,
|
||||
'color-scheduling-profiler-native-event-hover',
|
||||
documentElements,
|
||||
);
|
||||
updateStyleHelper(
|
||||
theme,
|
||||
'color-selected-tree-highlight-active',
|
||||
|
||||
@@ -79,8 +79,10 @@
|
||||
--light-color-record-inactive: #0088fa;
|
||||
--light-color-resize-bar: #cccccc;
|
||||
--light-color-scheduling-profiler-flame-graph-label: #000000;
|
||||
--light-color-scheduling-profiler-priority-background: #ededf0;
|
||||
--light-color-scheduling-profiler-priority-border: #d7d7db;
|
||||
--light-color-scheduling-profiler-native-event: #aaaaaa;
|
||||
--light-color-scheduling-profiler-native-event-hover: #888888;
|
||||
--light-color-scheduling-profiler-priority-background: #f6f6f6;
|
||||
--light-color-scheduling-profiler-priority-border: #eeeeee;
|
||||
--light-color-scheduling-profiler-user-timing: #c9cacd;
|
||||
--light-color-scheduling-profiler-user-timing-hover:#93959a;
|
||||
--light-color-scheduling-profiler-react-idle: #edf6ff;
|
||||
@@ -199,6 +201,8 @@
|
||||
--dark-color-record-inactive: #61dafb;
|
||||
--dark-color-resize-bar: #3d424a;
|
||||
--dark-color-scheduling-profiler-flame-graph-label: #000000;
|
||||
--dark-color-scheduling-profiler-native-event: #aaaaaa;
|
||||
--dark-color-scheduling-profiler-native-event-hover: #888888;
|
||||
--dark-color-scheduling-profiler-priority-background: #1d2129;
|
||||
--dark-color-scheduling-profiler-priority-border: #282c34;
|
||||
--dark-color-scheduling-profiler-user-timing: #c9cacd;
|
||||
|
||||
Reference in New Issue
Block a user