@@ -17,10 +17,10 @@ import type {
1717
1818import { enableProfilerTimer } from 'shared/ReactFeatureFlags' ;
1919
20- import { OMITTED_PROP_ERROR } from './ReactFlightPropertyAccess' ;
21-
22- import hasOwnProperty from 'shared/hasOwnProperty' ;
23- import isArray from 'shared/isArray ' ;
20+ import {
21+ addValueToProperties ,
22+ addObjectToProperties ,
23+ } from 'shared/ReactPerformanceTrackProperties ' ;
2424
2525const supportsUserTiming =
2626 enableProfilerTimer &&
@@ -33,127 +33,6 @@ const supportsUserTiming =
3333const IO_TRACK = 'Server Requests ⚛' ;
3434const COMPONENTS_TRACK = 'Server Components ⚛' ;
3535
36- const EMPTY_ARRAY = 0 ;
37- const COMPLEX_ARRAY = 1 ;
38- const PRIMITIVE_ARRAY = 2 ; // Primitive values only
39- const ENTRIES_ARRAY = 3 ; // Tuple arrays of string and value (like Headers, Map, etc)
40- function getArrayKind ( array : Object ) : 0 | 1 | 2 | 3 {
41- let kind = EMPTY_ARRAY ;
42- for ( let i = 0 ; i < array . length ; i ++ ) {
43- const value = array [ i ] ;
44- if ( typeof value === 'object' && value !== null ) {
45- if (
46- isArray ( value ) &&
47- value . length === 2 &&
48- typeof value [ 0 ] === 'string'
49- ) {
50- // Key value tuple
51- if ( kind !== EMPTY_ARRAY && kind !== ENTRIES_ARRAY ) {
52- return COMPLEX_ARRAY ;
53- }
54- kind = ENTRIES_ARRAY ;
55- } else {
56- return COMPLEX_ARRAY ;
57- }
58- } else if ( typeof value === 'function' ) {
59- return COMPLEX_ARRAY ;
60- } else if ( typeof value === 'string' && value . length > 50 ) {
61- return COMPLEX_ARRAY ;
62- } else if ( kind !== EMPTY_ARRAY && kind !== PRIMITIVE_ARRAY ) {
63- return COMPLEX_ARRAY ;
64- } else {
65- kind = PRIMITIVE_ARRAY ;
66- }
67- }
68- return kind ;
69- }
70-
71- function addObjectToProperties (
72- object : Object ,
73- properties : Array < [ string , string ] > ,
74- indent : number ,
75- ) : void {
76- for ( const key in object ) {
77- if ( hasOwnProperty . call ( object , key ) && key [ 0 ] !== '_' ) {
78- const value = object [ key ] ;
79- addValueToProperties ( key , value , properties , indent ) ;
80- }
81- }
82- }
83-
84- function addValueToProperties (
85- propertyName : string ,
86- value : mixed ,
87- properties : Array < [ string , string ] > ,
88- indent : number ,
89- ) : void {
90- let desc ;
91- switch ( typeof value ) {
92- case 'object' :
93- if ( value === null ) {
94- desc = 'null' ;
95- break ;
96- } else {
97- // $FlowFixMe[method-unbinding]
98- const objectToString = Object . prototype . toString . call ( value ) ;
99- let objectName = objectToString . slice ( 8 , objectToString . length - 1 ) ;
100- if ( objectName === 'Array' ) {
101- const array : Array < any > = (value: any);
102- const kind = getArrayKind(array);
103- if (kind === PRIMITIVE_ARRAY || kind === EMPTY_ARRAY) {
104- desc = JSON . stringify ( array ) ;
105- break ;
106- } else if (kind === ENTRIES_ARRAY) {
107- properties . push ( [ '\xa0\xa0' . repeat ( indent ) + propertyName , '' ] ) ;
108- for ( let i = 0 ; i < array . length ; i ++ ) {
109- const entry = array [ i ] ;
110- addValueToProperties ( entry [ 0 ] , entry [ 1 ] , properties , indent + 1 ) ;
111- }
112- return;
113- }
114- }
115- if ( objectName === 'Object ') {
116- const proto : any = Object . getPrototypeOf ( value ) ;
117- if ( proto && typeof proto . constructor === 'function' ) {
118- objectName = proto . constructor . name ;
119- }
120- }
121- properties . push ( [
122- '\xa0\xa0' . repeat ( indent ) + propertyName ,
123- objectName === 'Object' ? '' : objectName ,
124- ] ) ;
125- if ( indent < 3 ) {
126- addObjectToProperties ( value , properties , indent + 1 ) ;
127- }
128- return ;
129- }
130- case 'function' :
131- if ( value . name === '' ) {
132- desc = '() => {}' ;
133- } else {
134- desc = value . name + '() {}' ;
135- }
136- break ;
137- case 'string' :
138- if ( value === OMITTED_PROP_ERROR ) {
139- desc = '...' ;
140- } else {
141- desc = JSON . stringify ( value ) ;
142- }
143- break ;
144- case 'undefined' :
145- desc = 'undefined' ;
146- break ;
147- case 'boolean' :
148- desc = value ? 'true' : 'false' ;
149- break ;
150- default :
151- // eslint-disable-next-line react-internal/safe-string-coercion
152- desc = String ( value ) ;
153- }
154- properties . push ( [ '\xa0\xa0' . repeat ( indent ) + propertyName , desc ] ) ;
155- }
156-
15736export function markAllTracksInOrder ( ) {
15837 if ( supportsUserTiming ) {
15938 // Ensure we create the Server Component track groups earlier than the Client Scheduler
@@ -222,17 +101,27 @@ export function logComponentRender(
222101 isPrimaryEnv || env === undefined ? name : name + ' [' + env + ']' ;
223102 const debugTask = componentInfo . debugTask ;
224103 if ( __DEV__ && debugTask ) {
104+ const properties : Array < [ string , string ] > = [ ] ;
105+ if ( componentInfo . key != null ) {
106+ addValueToProperties ( 'key' , componentInfo . key , properties , 0 ) ;
107+ }
108+ if ( componentInfo . props != null ) {
109+ addObjectToProperties ( componentInfo . props , properties , 0 ) ;
110+ }
225111 debugTask . run (
226112 // $FlowFixMe[method-unbinding]
227- console . timeStamp . bind (
228- console ,
229- entryName ,
230- startTime < 0 ? 0 : startTime ,
231- childrenEndTime ,
232- trackNames [ trackIdx ] ,
233- COMPONENTS_TRACK ,
234- color ,
235- ) ,
113+ performance . measure . bind ( performance , entryName , {
114+ start : startTime < 0 ? 0 : startTime ,
115+ end : childrenEndTime ,
116+ detail : {
117+ devtools : {
118+ color : color ,
119+ track : trackNames [ trackIdx ] ,
120+ trackGroup : COMPONENTS_TRACK ,
121+ properties,
122+ } ,
123+ } ,
124+ } ) ,
236125 ) ;
237126 } else {
238127 console . timeStamp (
@@ -268,6 +157,12 @@ export function logComponentAborted(
268157 'The stream was aborted before this Component finished rendering.' ,
269158 ] ,
270159 ] ;
160+ if ( componentInfo . key != null ) {
161+ addValueToProperties ( 'key' , componentInfo . key , properties , 0 ) ;
162+ }
163+ if ( componentInfo . props != null ) {
164+ addObjectToProperties ( componentInfo . props , properties , 0 ) ;
165+ }
271166 performance . measure ( entryName , {
272167 start : startTime < 0 ? 0 : startTime ,
273168 end : childrenEndTime ,
@@ -319,6 +214,12 @@ export function logComponentErrored(
319214 : // eslint-disable-next-line react-internal/safe-string-coercion
320215 String ( error ) ;
321216 const properties = [ [ 'Error' , message ] ] ;
217+ if ( componentInfo . key != null ) {
218+ addValueToProperties ( 'key' , componentInfo . key , properties , 0 ) ;
219+ }
220+ if ( componentInfo . props != null ) {
221+ addObjectToProperties ( componentInfo . props , properties , 0 ) ;
222+ }
322223 performance . measure ( entryName , {
323224 start : startTime < 0 ? 0 : startTime ,
324225 end : childrenEndTime ,
0 commit comments