Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7398334948 |
@@ -9,7 +9,6 @@ import {
|
||||
import * as t from '@babel/types';
|
||||
import * as TypeErrors from './TypeErrors';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
import {FlowType} from './FlowTypes';
|
||||
|
||||
export const DEBUG = false;
|
||||
|
||||
@@ -197,6 +196,8 @@ export function makeVariableId(id: number): VariableId {
|
||||
return id as VariableId;
|
||||
}
|
||||
|
||||
import {inspect} from 'util';
|
||||
import {FlowType} from './FlowTypes';
|
||||
export function printConcrete<T>(
|
||||
type: ConcreteType<T>,
|
||||
printType: (_: T) => string,
|
||||
@@ -240,7 +241,7 @@ export function printConcrete<T>(
|
||||
case 'Generic':
|
||||
return `T${type.id}`;
|
||||
case 'Object': {
|
||||
const name = `Object [${[...type.members.keys()].map(key => JSON.stringify(key)).join(', ')}]`;
|
||||
const name = `Object ${inspect([...type.members.keys()])}`;
|
||||
return `${name}`;
|
||||
}
|
||||
case 'Tuple': {
|
||||
|
||||
@@ -892,7 +892,8 @@ export function printType(type: Type): string {
|
||||
if (type.kind === 'Object' && type.shapeId != null) {
|
||||
return `:T${type.kind}<${type.shapeId}>`;
|
||||
} else if (type.kind === 'Function' && type.shapeId != null) {
|
||||
return `:T${type.kind}<${type.shapeId}>`;
|
||||
const returnType = printType(type.return);
|
||||
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
|
||||
} else {
|
||||
return `:T${type.kind}`;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
InstructionKind,
|
||||
InstructionValue,
|
||||
isArrayType,
|
||||
isJsxType,
|
||||
isMapType,
|
||||
isPrimitiveType,
|
||||
isRefOrRefValue,
|
||||
@@ -1841,6 +1842,23 @@ function computeSignatureForInstruction(
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const prop of value.props) {
|
||||
if (
|
||||
prop.kind === 'JsxAttribute' &&
|
||||
prop.place.identifier.type.kind === 'Function' &&
|
||||
(isJsxType(prop.place.identifier.type.return) ||
|
||||
(prop.place.identifier.type.return.kind === 'Phi' &&
|
||||
prop.place.identifier.type.return.operands.some(operand =>
|
||||
isJsxType(operand),
|
||||
)))
|
||||
) {
|
||||
// Any props which return jsx are assumed to be called during render
|
||||
effects.push({
|
||||
kind: 'Render',
|
||||
place: prop.place,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1810,70 +1810,41 @@ function codegenInstructionValue(
|
||||
case 'MethodCall': {
|
||||
const isHook =
|
||||
getHookKind(cx.env, instrValue.property.identifier) != null;
|
||||
/**
|
||||
* We need to check if the property was memoized. If it has, we should reconstruct the
|
||||
* MemberExpression.
|
||||
*/
|
||||
let memberExpr: t.Expression;
|
||||
const tmp = cx.temp.get(instrValue.property.identifier.declarationId);
|
||||
if (tmp != null && tmp.type === 'Identifier') {
|
||||
/**
|
||||
* We can't reconstruct the MemberExpression from just the identifier, so we work around
|
||||
* this by allowing an Identifier here.
|
||||
*/
|
||||
memberExpr = tmp;
|
||||
} else if (tmp != null) {
|
||||
memberExpr = convertValueToExpression(tmp);
|
||||
} else {
|
||||
memberExpr = codegenPlaceToExpression(cx, instrValue.property);
|
||||
}
|
||||
|
||||
// Reconstruct the MemberExpression if we previously saw an Identifier.
|
||||
if (memberExpr.type === 'Identifier') {
|
||||
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
||||
value = createCallExpression(
|
||||
cx.env,
|
||||
memberExpr,
|
||||
args,
|
||||
instrValue.loc,
|
||||
isHook,
|
||||
);
|
||||
} else {
|
||||
CompilerError.invariant(
|
||||
t.isMemberExpression(memberExpr) ||
|
||||
t.isOptionalMemberExpression(memberExpr),
|
||||
{
|
||||
reason:
|
||||
'[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. ' +
|
||||
`Got a \`${memberExpr.type}\``,
|
||||
description: null,
|
||||
loc: memberExpr.loc ?? null,
|
||||
suggestions: null,
|
||||
},
|
||||
);
|
||||
CompilerError.invariant(
|
||||
t.isNodesEquivalent(
|
||||
memberExpr.object,
|
||||
codegenPlaceToExpression(cx, instrValue.receiver),
|
||||
),
|
||||
{
|
||||
reason:
|
||||
'[Codegen] Internal error: Forget should always generate MethodCall::property ' +
|
||||
'as a MemberExpression of MethodCall::receiver',
|
||||
description: null,
|
||||
loc: memberExpr.loc ?? null,
|
||||
suggestions: null,
|
||||
},
|
||||
);
|
||||
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
||||
value = createCallExpression(
|
||||
cx.env,
|
||||
memberExpr,
|
||||
args,
|
||||
instrValue.loc,
|
||||
isHook,
|
||||
);
|
||||
}
|
||||
const memberExpr = codegenPlaceToExpression(cx, instrValue.property);
|
||||
CompilerError.invariant(
|
||||
t.isMemberExpression(memberExpr) ||
|
||||
t.isOptionalMemberExpression(memberExpr),
|
||||
{
|
||||
reason:
|
||||
'[Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. ' +
|
||||
`Got a \`${memberExpr.type}\``,
|
||||
description: null,
|
||||
loc: memberExpr.loc ?? null,
|
||||
suggestions: null,
|
||||
},
|
||||
);
|
||||
CompilerError.invariant(
|
||||
t.isNodesEquivalent(
|
||||
memberExpr.object,
|
||||
codegenPlaceToExpression(cx, instrValue.receiver),
|
||||
),
|
||||
{
|
||||
reason:
|
||||
'[Codegen] Internal error: Forget should always generate MethodCall::property ' +
|
||||
'as a MemberExpression of MethodCall::receiver',
|
||||
description: null,
|
||||
loc: memberExpr.loc ?? null,
|
||||
suggestions: null,
|
||||
},
|
||||
);
|
||||
const args = instrValue.args.map(arg => codegenArgument(cx, arg));
|
||||
value = createCallExpression(
|
||||
cx.env,
|
||||
memberExpr,
|
||||
args,
|
||||
instrValue.loc,
|
||||
isHook,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'NewExpression': {
|
||||
|
||||
@@ -777,6 +777,15 @@ class Unifier {
|
||||
return {kind: 'Phi', operands: type.operands.map(o => this.get(o))};
|
||||
}
|
||||
|
||||
if (type.kind === 'Function') {
|
||||
return {
|
||||
kind: 'Function',
|
||||
isConstructor: type.isConstructor,
|
||||
shapeId: type.shapeId,
|
||||
return: this.get(type.return),
|
||||
};
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {PrimitiveBox} from 'shared-runtime';
|
||||
|
||||
function Component({value, realmax}) {
|
||||
const box = new PrimitiveBox(value);
|
||||
const maxValue = Math.max(box.get(), realmax);
|
||||
// ^^^^^^^^^ should not be separated into static call
|
||||
return <div>{maxValue}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42, realmax: 100}],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { PrimitiveBox } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(6);
|
||||
const { value, realmax } = t0;
|
||||
let t1;
|
||||
let t2;
|
||||
let t3;
|
||||
if ($[0] !== value) {
|
||||
const box = new PrimitiveBox(value);
|
||||
t1 = Math;
|
||||
t2 = t1.max;
|
||||
t3 = box.get();
|
||||
$[0] = value;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
t3 = $[3];
|
||||
}
|
||||
const maxValue = t2(t3, realmax);
|
||||
let t4;
|
||||
if ($[4] !== maxValue) {
|
||||
t4 = <div>{maxValue}</div>;
|
||||
$[4] = maxValue;
|
||||
$[5] = t4;
|
||||
} else {
|
||||
t4 = $[5];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ value: 42, realmax: 100 }],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>100</div>
|
||||
@@ -1,14 +0,0 @@
|
||||
import {PrimitiveBox} from 'shared-runtime';
|
||||
|
||||
function Component({value, realmax}) {
|
||||
const box = new PrimitiveBox(value);
|
||||
const maxValue = Math.max(box.get(), realmax);
|
||||
// ^^^^^^^^^ should not be separated into static call
|
||||
return <div>{maxValue}</div>;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{value: 42, realmax: 100}],
|
||||
isComponent: true,
|
||||
};
|
||||
@@ -1,85 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
return {
|
||||
bar() {
|
||||
return 3.14;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const YearsAndMonthsSince = () => {
|
||||
const diff = foo();
|
||||
const months = Math.floor(diff.bar());
|
||||
return <>{months}</>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: YearsAndMonthsSince,
|
||||
params: [],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
function foo() {
|
||||
const $ = _c(1);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = {
|
||||
bar() {
|
||||
return 3.14;
|
||||
},
|
||||
};
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
|
||||
const YearsAndMonthsSince = () => {
|
||||
const $ = _c(4);
|
||||
let t0;
|
||||
let t1;
|
||||
let t2;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const diff = foo();
|
||||
t0 = Math;
|
||||
t1 = t0.floor;
|
||||
t2 = diff.bar();
|
||||
$[0] = t0;
|
||||
$[1] = t1;
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
t1 = $[1];
|
||||
t2 = $[2];
|
||||
}
|
||||
const months = t1(t2);
|
||||
let t3;
|
||||
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t3 = <>{months}</>;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
return t3;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: YearsAndMonthsSince,
|
||||
params: [],
|
||||
isComponent: true,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) 3
|
||||
@@ -1,19 +0,0 @@
|
||||
function foo() {
|
||||
return {
|
||||
bar() {
|
||||
return 3.14;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const YearsAndMonthsSince = () => {
|
||||
const diff = foo();
|
||||
const months = Math.floor(diff.bar());
|
||||
return <>{months}</>;
|
||||
};
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: YearsAndMonthsSince,
|
||||
params: [],
|
||||
isComponent: true,
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
const YearsAndMonthsSince = () => {
|
||||
const diff = foo();
|
||||
const months = Math.floor(diff.bar());
|
||||
return <>{months}</>;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
|
||||
|
||||
error.bug-invariant-codegen-methodcall.ts:3:17
|
||||
1 | const YearsAndMonthsSince = () => {
|
||||
2 | const diff = foo();
|
||||
> 3 | const months = Math.floor(diff.bar());
|
||||
| ^^^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
|
||||
4 | return <>{months}</>;
|
||||
5 | };
|
||||
6 |
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const YearsAndMonthsSince = () => {
|
||||
const diff = foo();
|
||||
const months = Math.floor(diff.bar());
|
||||
return <>{months}</>;
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component() {
|
||||
const renderItem = item => {
|
||||
// Multiple returns so that the return type is a Phi (union)
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
// Normally we assume that it's safe to mutate globals in a function passed
|
||||
// as a prop, because the prop could be used as an event handler or effect.
|
||||
// But if the function returns JSX we can assume it's a render helper, ie
|
||||
// called during render, and thus it's unsafe to mutate globals or call
|
||||
// other impure code.
|
||||
global.property = true;
|
||||
return <Item item={item} value={rand} />;
|
||||
};
|
||||
return <ItemList renderItem={renderItem} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Error: This value cannot be modified
|
||||
|
||||
Modifying a variable defined outside a component or hook is not allowed. Consider using an effect.
|
||||
|
||||
error.invalid-mutate-global-in-render-helper-phi-return-prop.ts:12:4
|
||||
10 | // called during render, and thus it's unsafe to mutate globals or call
|
||||
11 | // other impure code.
|
||||
> 12 | global.property = true;
|
||||
| ^^^^^^ value cannot be modified
|
||||
13 | return <Item item={item} value={rand} />;
|
||||
14 | };
|
||||
15 | return <ItemList renderItem={renderItem} />;
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
function Component() {
|
||||
const renderItem = item => {
|
||||
// Multiple returns so that the return type is a Phi (union)
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
// Normally we assume that it's safe to mutate globals in a function passed
|
||||
// as a prop, because the prop could be used as an event handler or effect.
|
||||
// But if the function returns JSX we can assume it's a render helper, ie
|
||||
// called during render, and thus it's unsafe to mutate globals or call
|
||||
// other impure code.
|
||||
global.property = true;
|
||||
return <Item item={item} value={rand} />;
|
||||
};
|
||||
return <ItemList renderItem={renderItem} />;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function Component() {
|
||||
const renderItem = item => {
|
||||
// Normally we assume that it's safe to mutate globals in a function passed
|
||||
// as a prop, because the prop could be used as an event handler or effect.
|
||||
// But if the function returns JSX we can assume it's a render helper, ie
|
||||
// called during render, and thus it's unsafe to mutate globals or call
|
||||
// other impure code.
|
||||
global.property = true;
|
||||
return <Item item={item} value={rand} />;
|
||||
};
|
||||
return <ItemList renderItem={renderItem} />;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Error: This value cannot be modified
|
||||
|
||||
Modifying a variable defined outside a component or hook is not allowed. Consider using an effect.
|
||||
|
||||
error.invalid-mutate-global-in-render-helper-prop.ts:8:4
|
||||
6 | // called during render, and thus it's unsafe to mutate globals or call
|
||||
7 | // other impure code.
|
||||
> 8 | global.property = true;
|
||||
| ^^^^^^ value cannot be modified
|
||||
9 | return <Item item={item} value={rand} />;
|
||||
10 | };
|
||||
11 | return <ItemList renderItem={renderItem} />;
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
function Component() {
|
||||
const renderItem = item => {
|
||||
// Normally we assume that it's safe to mutate globals in a function passed
|
||||
// as a prop, because the prop could be used as an event handler or effect.
|
||||
// But if the function returns JSX we can assume it's a render helper, ie
|
||||
// called during render, and thus it's unsafe to mutate globals or call
|
||||
// other impure code.
|
||||
global.property = true;
|
||||
return <Item item={item} value={rand} />;
|
||||
};
|
||||
return <ItemList renderItem={renderItem} />;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {makeArray} from 'shared-runtime';
|
||||
|
||||
const other = [0, 1];
|
||||
function Component({}) {
|
||||
const items = makeArray(0, 1, 2, null, 4, false, 6);
|
||||
const max = Math.max(2, items.push(5), ...other);
|
||||
return max;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Found 1 error:
|
||||
|
||||
Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
|
||||
|
||||
error.todo-nested-method-calls-lower-property-load-into-temporary.ts:6:14
|
||||
4 | function Component({}) {
|
||||
5 | const items = makeArray(0, 1, 2, null, 4, false, 6);
|
||||
> 6 | const max = Math.max(2, items.push(5), ...other);
|
||||
| ^^^^^^^^ [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier`
|
||||
7 | return max;
|
||||
8 | }
|
||||
9 |
|
||||
```
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {makeArray} from 'shared-runtime';
|
||||
|
||||
const other = [0, 1];
|
||||
function Component({}) {
|
||||
const items = makeArray(0, 1, 2, null, 4, false, 6);
|
||||
const max = Math.max(2, items.push(5), ...other);
|
||||
return max;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { makeArray } from "shared-runtime";
|
||||
|
||||
const other = [0, 1];
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
let t1;
|
||||
let t2;
|
||||
let t3;
|
||||
let t4;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
const items = makeArray(0, 1, 2, null, 4, false, 6);
|
||||
t1 = Math;
|
||||
t2 = t1.max;
|
||||
t3 = 2;
|
||||
t4 = items.push(5);
|
||||
$[0] = t1;
|
||||
$[1] = t2;
|
||||
$[2] = t3;
|
||||
$[3] = t4;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
t2 = $[1];
|
||||
t3 = $[2];
|
||||
t4 = $[3];
|
||||
}
|
||||
const max = t2(t3, t4, ...other);
|
||||
return max;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) 8
|
||||
@@ -196,29 +196,6 @@ export function makeSharedRuntimeTypeProvider({
|
||||
],
|
||||
},
|
||||
},
|
||||
PrimitiveBox: {
|
||||
kind: 'object',
|
||||
properties: {
|
||||
get: {
|
||||
kind: 'function',
|
||||
positionalParams: [],
|
||||
restParam: null,
|
||||
calleeEffect: EffectEnum.Read,
|
||||
returnType: {kind: 'type', name: 'Primitive'},
|
||||
returnValueKind: ValueKindEnum.Primitive,
|
||||
aliasing: {
|
||||
receiver: '@receiver',
|
||||
params: ['@value'],
|
||||
rest: null,
|
||||
returns: '@return',
|
||||
temporaries: [],
|
||||
effects: [
|
||||
{kind: 'CreateFrom', from: '@value', into: '@return'},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} else if (moduleName === 'ReactCompilerTest') {
|
||||
|
||||
@@ -421,22 +421,4 @@ export function typedMutate(x: any, v: any = null): void {
|
||||
x.property = v;
|
||||
}
|
||||
|
||||
type PrimitiveValue =
|
||||
| number
|
||||
| string
|
||||
| boolean
|
||||
| symbol
|
||||
| null
|
||||
| undefined
|
||||
| bigint;
|
||||
export class PrimitiveBox<T extends PrimitiveValue> {
|
||||
value: T;
|
||||
constructor(value: T) {
|
||||
this.value = value;
|
||||
}
|
||||
get(): T {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
export default typedLog;
|
||||
|
||||
94
packages/react-client/src/ReactFlightClient.js
vendored
94
packages/react-client/src/ReactFlightClient.js
vendored
@@ -1969,44 +1969,6 @@ function createModel(response: Response, model: any): any {
|
||||
return model;
|
||||
}
|
||||
|
||||
const mightHaveStaticConstructor = /\bclass\b.*\bstatic\b/;
|
||||
|
||||
function getInferredFunctionApproximate(code: string): () => void {
|
||||
let slicedCode;
|
||||
if (code.startsWith('Object.defineProperty(')) {
|
||||
slicedCode = code.slice('Object.defineProperty('.length);
|
||||
} else if (code.startsWith('(')) {
|
||||
slicedCode = code.slice(1);
|
||||
} else {
|
||||
slicedCode = code;
|
||||
}
|
||||
if (slicedCode.startsWith('async function')) {
|
||||
const idx = slicedCode.indexOf('(', 14);
|
||||
if (idx !== -1) {
|
||||
const name = slicedCode.slice(14, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)('({' + JSON.stringify(name) + ':async function(){}})')[
|
||||
name
|
||||
];
|
||||
}
|
||||
} else if (slicedCode.startsWith('function')) {
|
||||
const idx = slicedCode.indexOf('(', 8);
|
||||
if (idx !== -1) {
|
||||
const name = slicedCode.slice(8, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)('({' + JSON.stringify(name) + ':function(){}})')[name];
|
||||
}
|
||||
} else if (slicedCode.startsWith('class')) {
|
||||
const idx = slicedCode.indexOf('{', 5);
|
||||
if (idx !== -1) {
|
||||
const name = slicedCode.slice(5, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)('({' + JSON.stringify(name) + ':class{}})')[name];
|
||||
}
|
||||
}
|
||||
return function () {};
|
||||
}
|
||||
|
||||
function parseModelString(
|
||||
response: Response,
|
||||
parentObject: Object,
|
||||
@@ -2196,37 +2158,41 @@ function parseModelString(
|
||||
// This should not compile to eval() because then it has local scope access.
|
||||
const code = value.slice(2);
|
||||
try {
|
||||
// If this might be a class constructor with a static initializer or
|
||||
// static constructor then don't eval it. It might cause unexpected
|
||||
// side-effects. Instead, fallback to parsing out the function type
|
||||
// and name.
|
||||
if (!mightHaveStaticConstructor.test(code)) {
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)(code);
|
||||
}
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)(code);
|
||||
} catch (x) {
|
||||
// Fallthrough to fallback case.
|
||||
}
|
||||
// We currently use this to express functions so we fail parsing it,
|
||||
// let's just return a blank function as a place holder.
|
||||
let fn;
|
||||
try {
|
||||
fn = getInferredFunctionApproximate(code);
|
||||
if (code.startsWith('Object.defineProperty(')) {
|
||||
const DESCRIPTOR = ',"name",{value:"';
|
||||
const idx = code.lastIndexOf(DESCRIPTOR);
|
||||
// We currently use this to express functions so we fail parsing it,
|
||||
// let's just return a blank function as a place holder.
|
||||
if (code.startsWith('(async function')) {
|
||||
const idx = code.indexOf('(', 15);
|
||||
if (idx !== -1) {
|
||||
const name = JSON.parse(
|
||||
code.slice(idx + DESCRIPTOR.length - 1, code.length - 2),
|
||||
);
|
||||
// $FlowFixMe[cannot-write]
|
||||
Object.defineProperty(fn, 'name', {value: name});
|
||||
const name = code.slice(15, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)(
|
||||
'({' + JSON.stringify(name) + ':async function(){}})',
|
||||
)[name];
|
||||
}
|
||||
} else if (code.startsWith('(function')) {
|
||||
const idx = code.indexOf('(', 9);
|
||||
if (idx !== -1) {
|
||||
const name = code.slice(9, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)(
|
||||
'({' + JSON.stringify(name) + ':function(){}})',
|
||||
)[name];
|
||||
}
|
||||
} else if (code.startsWith('(class')) {
|
||||
const idx = code.indexOf('{', 6);
|
||||
if (idx !== -1) {
|
||||
const name = code.slice(6, idx).trim();
|
||||
// eslint-disable-next-line no-eval
|
||||
return (0, eval)('({' + JSON.stringify(name) + ':class{}})')[
|
||||
name
|
||||
];
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
fn = function () {};
|
||||
return function () {};
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
// Fallthrough
|
||||
}
|
||||
|
||||
@@ -3239,8 +3239,6 @@ describe('ReactFlight', () => {
|
||||
}
|
||||
Object.defineProperty(MyClass.prototype, 'y', {enumerable: true});
|
||||
|
||||
Object.defineProperty(MyClass, 'name', {value: 'MyClassName'});
|
||||
|
||||
function ServerComponent() {
|
||||
console.log('hi', {
|
||||
prop: 123,
|
||||
@@ -3343,7 +3341,6 @@ describe('ReactFlight', () => {
|
||||
const instance = mockConsoleLog.mock.calls[0][1].instance;
|
||||
expect(typeof Class).toBe('function');
|
||||
expect(Class.prototype.constructor).toBe(Class);
|
||||
expect(Class.name).toBe('MyClassName');
|
||||
expect(instance instanceof Class).toBe(true);
|
||||
expect(Object.getPrototypeOf(instance)).toBe(Class.prototype);
|
||||
expect(instance.x).toBe(1);
|
||||
|
||||
@@ -862,7 +862,6 @@ describe('ProfilingCache', () => {
|
||||
{
|
||||
"compiledWithForget": false,
|
||||
"displayName": "render()",
|
||||
"env": null,
|
||||
"hocDisplayNames": null,
|
||||
"id": 1,
|
||||
"key": null,
|
||||
@@ -904,7 +903,6 @@ describe('ProfilingCache', () => {
|
||||
{
|
||||
"compiledWithForget": false,
|
||||
"displayName": "createRoot()",
|
||||
"env": null,
|
||||
"hocDisplayNames": null,
|
||||
"id": 1,
|
||||
"key": null,
|
||||
@@ -945,7 +943,6 @@ describe('ProfilingCache', () => {
|
||||
{
|
||||
"compiledWithForget": false,
|
||||
"displayName": "createRoot()",
|
||||
"env": null,
|
||||
"hocDisplayNames": null,
|
||||
"id": 1,
|
||||
"key": null,
|
||||
|
||||
@@ -4818,7 +4818,6 @@ export function attach(
|
||||
displayName: getDisplayNameForFiber(fiber) || 'Anonymous',
|
||||
id: instance.id,
|
||||
key: fiber.key,
|
||||
env: null,
|
||||
type: getElementTypeForFiber(fiber),
|
||||
};
|
||||
} else {
|
||||
@@ -4827,7 +4826,6 @@ export function attach(
|
||||
displayName: componentInfo.name || 'Anonymous',
|
||||
id: instance.id,
|
||||
key: componentInfo.key == null ? null : componentInfo.key,
|
||||
env: componentInfo.env == null ? null : componentInfo.env,
|
||||
type: ElementTypeVirtual,
|
||||
};
|
||||
}
|
||||
@@ -5453,8 +5451,6 @@ export function attach(
|
||||
// List of owners
|
||||
owners,
|
||||
|
||||
env: null,
|
||||
|
||||
rootType,
|
||||
rendererPackageName: renderer.rendererPackageName,
|
||||
rendererVersion: renderer.version,
|
||||
@@ -5558,8 +5554,6 @@ export function attach(
|
||||
// List of owners
|
||||
owners,
|
||||
|
||||
env: componentInfo.env == null ? null : componentInfo.env,
|
||||
|
||||
rootType,
|
||||
rendererPackageName: renderer.rendererPackageName,
|
||||
rendererVersion: renderer.version,
|
||||
|
||||
@@ -795,7 +795,6 @@ export function attach(
|
||||
displayName: getData(owner).displayName || 'Unknown',
|
||||
id: getID(owner),
|
||||
key: element.key,
|
||||
env: null,
|
||||
type: getElementType(owner),
|
||||
});
|
||||
if (owner._currentElement) {
|
||||
@@ -858,8 +857,6 @@ export function attach(
|
||||
// List of owners
|
||||
owners,
|
||||
|
||||
env: null,
|
||||
|
||||
rootType: null,
|
||||
rendererPackageName: null,
|
||||
rendererVersion: null,
|
||||
|
||||
@@ -256,7 +256,6 @@ export type SerializedElement = {
|
||||
displayName: string | null,
|
||||
id: number,
|
||||
key: number | string | null,
|
||||
env: null | string,
|
||||
type: ElementType,
|
||||
};
|
||||
|
||||
@@ -302,10 +301,6 @@ export type InspectedElement = {
|
||||
|
||||
// List of owners
|
||||
owners: Array<SerializedElement> | null,
|
||||
|
||||
// Environment name that this component executed in or null for the client
|
||||
env: string | null,
|
||||
|
||||
source: ReactFunctionLocation | null,
|
||||
|
||||
type: ElementType,
|
||||
|
||||
@@ -255,7 +255,6 @@ export function convertInspectedElementBackendToFrontend(
|
||||
id,
|
||||
type,
|
||||
owners,
|
||||
env,
|
||||
source,
|
||||
context,
|
||||
hooks,
|
||||
@@ -300,7 +299,6 @@ export function convertInspectedElementBackendToFrontend(
|
||||
owners === null
|
||||
? null
|
||||
: owners.map(backendToFrontendSerializedElementMapper),
|
||||
env,
|
||||
context: hydrateHelper(context),
|
||||
hooks: hydrateHelper(hooks),
|
||||
props: hydrateHelper(props),
|
||||
|
||||
@@ -16,21 +16,18 @@ import styles from './ElementBadges.css';
|
||||
|
||||
type Props = {
|
||||
hocDisplayNames: Array<string> | null,
|
||||
environmentName: string | null,
|
||||
compiledWithForget: boolean,
|
||||
className?: string,
|
||||
};
|
||||
|
||||
export default function ElementBadges({
|
||||
compiledWithForget,
|
||||
environmentName,
|
||||
hocDisplayNames,
|
||||
className = '',
|
||||
}: Props): React.Node {
|
||||
if (
|
||||
!compiledWithForget &&
|
||||
(hocDisplayNames == null || hocDisplayNames.length === 0) &&
|
||||
environmentName == null
|
||||
(hocDisplayNames == null || hocDisplayNames.length === 0)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
@@ -39,8 +36,6 @@ export default function ElementBadges({
|
||||
<div className={`${styles.Root} ${className}`}>
|
||||
{compiledWithForget && <ForgetBadge indexable={false} />}
|
||||
|
||||
{environmentName != null ? <Badge>{environmentName}</Badge> : null}
|
||||
|
||||
{hocDisplayNames != null && hocDisplayNames.length > 0 && (
|
||||
<Badge>{hocDisplayNames[0]}</Badge>
|
||||
)}
|
||||
|
||||
@@ -150,28 +150,13 @@ function SuspendedByRow({
|
||||
</Button>
|
||||
{isOpen && (
|
||||
<div className={styles.CollapsableContent}>
|
||||
{showIOStack && (
|
||||
<StackTraceView
|
||||
stack={ioInfo.stack}
|
||||
environmentName={
|
||||
ioOwner !== null && ioOwner.env === ioInfo.env
|
||||
? null
|
||||
: ioInfo.env
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{showIOStack && <StackTraceView stack={ioInfo.stack} />}
|
||||
{(showIOStack || !showAwaitStack) &&
|
||||
ioOwner !== null &&
|
||||
ioOwner.id !== inspectedElement.id ? (
|
||||
<OwnerView
|
||||
key={ioOwner.id}
|
||||
displayName={ioOwner.displayName || 'Anonymous'}
|
||||
environmentName={
|
||||
ioOwner.env === inspectedElement.env &&
|
||||
ioOwner.env === ioInfo.env
|
||||
? null
|
||||
: ioOwner.env
|
||||
}
|
||||
hocDisplayNames={ioOwner.hocDisplayNames}
|
||||
compiledWithForget={ioOwner.compiledWithForget}
|
||||
id={ioOwner.id}
|
||||
@@ -183,25 +168,12 @@ function SuspendedByRow({
|
||||
<>
|
||||
<div className={styles.SmallHeader}>awaited at:</div>
|
||||
{asyncInfo.stack !== null && asyncInfo.stack.length > 0 && (
|
||||
<StackTraceView
|
||||
stack={asyncInfo.stack}
|
||||
environmentName={
|
||||
asyncOwner !== null && asyncOwner.env === asyncInfo.env
|
||||
? null
|
||||
: asyncInfo.env
|
||||
}
|
||||
/>
|
||||
<StackTraceView stack={asyncInfo.stack} />
|
||||
)}
|
||||
{asyncOwner !== null && asyncOwner.id !== inspectedElement.id ? (
|
||||
<OwnerView
|
||||
key={asyncOwner.id}
|
||||
displayName={asyncOwner.displayName || 'Anonymous'}
|
||||
environmentName={
|
||||
asyncOwner.env === inspectedElement.env &&
|
||||
asyncOwner.env === asyncInfo.env
|
||||
? null
|
||||
: asyncOwner.env
|
||||
}
|
||||
hocDisplayNames={asyncOwner.hocDisplayNames}
|
||||
compiledWithForget={asyncOwner.compiledWithForget}
|
||||
id={asyncOwner.id}
|
||||
|
||||
@@ -174,9 +174,6 @@ export default function InspectedElementView({
|
||||
key={owner.id}
|
||||
displayName={owner.displayName || 'Anonymous'}
|
||||
hocDisplayNames={owner.hocDisplayNames}
|
||||
environmentName={
|
||||
inspectedElement.env === owner.env ? null : owner.env
|
||||
}
|
||||
compiledWithForget={owner.compiledWithForget}
|
||||
id={owner.id}
|
||||
isInStore={store.containsElement(owner.id)}
|
||||
|
||||
@@ -20,7 +20,6 @@ import styles from './OwnerView.css';
|
||||
type OwnerViewProps = {
|
||||
displayName: string,
|
||||
hocDisplayNames: Array<string> | null,
|
||||
environmentName: string | null,
|
||||
compiledWithForget: boolean,
|
||||
id: number,
|
||||
isInStore: boolean,
|
||||
@@ -28,7 +27,6 @@ type OwnerViewProps = {
|
||||
|
||||
export default function OwnerView({
|
||||
displayName,
|
||||
environmentName,
|
||||
hocDisplayNames,
|
||||
compiledWithForget,
|
||||
id,
|
||||
@@ -67,7 +65,6 @@ export default function OwnerView({
|
||||
<ElementBadges
|
||||
hocDisplayNames={hocDisplayNames}
|
||||
compiledWithForget={compiledWithForget}
|
||||
environmentName={environmentName}
|
||||
/>
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
@@ -220,7 +220,6 @@ function ElementsDropdown({owners, selectOwner}: ElementsDropdownProps) {
|
||||
|
||||
<ElementBadges
|
||||
hocDisplayNames={owner.hocDisplayNames}
|
||||
environmentName={owner.env}
|
||||
compiledWithForget={owner.compiledWithForget}
|
||||
className={styles.BadgesBlock}
|
||||
/>
|
||||
@@ -269,7 +268,6 @@ function ElementView({isSelected, owner, selectOwner}: ElementViewProps) {
|
||||
|
||||
<ElementBadges
|
||||
hocDisplayNames={hocDisplayNames}
|
||||
environmentName={owner.env}
|
||||
compiledWithForget={compiledWithForget}
|
||||
className={styles.BadgesBlock}
|
||||
/>
|
||||
|
||||
@@ -12,8 +12,6 @@ import {use, useContext} from 'react';
|
||||
|
||||
import useOpenResource from '../useOpenResource';
|
||||
|
||||
import ElementBadges from './ElementBadges';
|
||||
|
||||
import styles from './StackTraceView.css';
|
||||
|
||||
import type {
|
||||
@@ -30,13 +28,9 @@ import formatLocationForDisplay from './formatLocationForDisplay';
|
||||
|
||||
type CallSiteViewProps = {
|
||||
callSite: ReactCallSite,
|
||||
environmentName: null | string,
|
||||
};
|
||||
|
||||
export function CallSiteView({
|
||||
callSite,
|
||||
environmentName,
|
||||
}: CallSiteViewProps): React.Node {
|
||||
export function CallSiteView({callSite}: CallSiteViewProps): React.Node {
|
||||
const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
|
||||
|
||||
const [virtualFunctionName, virtualURL, virtualLine, virtualColumn] =
|
||||
@@ -70,33 +64,19 @@ export function CallSiteView({
|
||||
title={url + ':' + line}>
|
||||
{formatLocationForDisplay(url, line, column)}
|
||||
</span>
|
||||
<ElementBadges environmentName={environmentName} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type Props = {
|
||||
stack: ReactStackTrace,
|
||||
environmentName: null | string,
|
||||
};
|
||||
|
||||
export default function StackTraceView({
|
||||
stack,
|
||||
environmentName,
|
||||
}: Props): React.Node {
|
||||
export default function StackTraceView({stack}: Props): React.Node {
|
||||
return (
|
||||
<div className={styles.StackTraceView}>
|
||||
{stack.map((callSite, index) => (
|
||||
<CallSiteView
|
||||
key={index}
|
||||
callSite={callSite}
|
||||
environmentName={
|
||||
// Badge last row
|
||||
// TODO: If we start ignore listing the last row, we should badge the last
|
||||
// non-ignored row.
|
||||
index === stack.length - 1 ? environmentName : null
|
||||
}
|
||||
/>
|
||||
<CallSiteView key={index} callSite={callSite} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -954,7 +954,7 @@ function TreeContextController({
|
||||
Array<number>,
|
||||
Map<number, number>,
|
||||
]) => {
|
||||
dispatch({
|
||||
transitionDispatch({
|
||||
type: 'HANDLE_STORE_MUTATION',
|
||||
payload: [addedElementIDs, removedElementIDs],
|
||||
});
|
||||
@@ -965,7 +965,7 @@ function TreeContextController({
|
||||
// At the moment, we can treat this as a mutation.
|
||||
// We don't know which Elements were newly added/removed, but that should be okay in this case.
|
||||
// It would only impact the search state, which is unlikely to exist yet at this point.
|
||||
dispatch({
|
||||
transitionDispatch({
|
||||
type: 'HANDLE_STORE_MUTATION',
|
||||
payload: [[], new Map()],
|
||||
});
|
||||
|
||||
@@ -208,7 +208,6 @@ export type SerializedElement = {
|
||||
displayName: string | null,
|
||||
id: number,
|
||||
key: number | string | null,
|
||||
env: null | string,
|
||||
hocDisplayNames: Array<string> | null,
|
||||
compiledWithForget: boolean,
|
||||
type: ElementType,
|
||||
@@ -266,9 +265,6 @@ export type InspectedElement = {
|
||||
// List of owners
|
||||
owners: Array<SerializedElement> | null,
|
||||
|
||||
// Environment name that this component executed in or null for the client
|
||||
env: string | null,
|
||||
|
||||
// Location of component in source code.
|
||||
source: ReactFunctionLocation | null,
|
||||
|
||||
|
||||
@@ -158,7 +158,6 @@ import {
|
||||
DefaultHydrationLane,
|
||||
SomeRetryLane,
|
||||
includesSomeLane,
|
||||
includesOnlyRetries,
|
||||
laneToLanes,
|
||||
removeLanes,
|
||||
mergeLanes,
|
||||
@@ -270,7 +269,6 @@ import {
|
||||
scheduleUpdateOnFiber,
|
||||
renderDidSuspendDelayIfPossible,
|
||||
markSkippedUpdateLanes,
|
||||
markRenderDerivedCause,
|
||||
getWorkInProgressRoot,
|
||||
peekDeferredLane,
|
||||
} from './ReactFiberWorkLoop';
|
||||
@@ -948,13 +946,6 @@ function updateDehydratedActivityComponent(
|
||||
// but after we've already committed once.
|
||||
warnIfHydrating();
|
||||
|
||||
if (includesSomeLane(renderLanes, (OffscreenLane: Lane))) {
|
||||
// If we're rendering Offscreen and we're entering the activity then it's possible
|
||||
// that the only reason we rendered was because this boundary left work. Provide
|
||||
// it as a cause if another one doesn't already exist.
|
||||
markRenderDerivedCause(workInProgress);
|
||||
}
|
||||
|
||||
if (
|
||||
// TODO: Factoring is a little weird, since we check this right below, too.
|
||||
!didReceiveUpdate
|
||||
@@ -1141,16 +1132,6 @@ function updateActivityComponent(
|
||||
children: nextChildren,
|
||||
};
|
||||
|
||||
if (
|
||||
includesSomeLane(renderLanes, (OffscreenLane: Lane)) &&
|
||||
includesSomeLane(renderLanes, current.lanes)
|
||||
) {
|
||||
// If we're rendering Offscreen and we're entering the activity then it's possible
|
||||
// that the only reason we rendered was because this boundary left work. Provide
|
||||
// it as a cause if another one doesn't already exist.
|
||||
markRenderDerivedCause(workInProgress);
|
||||
}
|
||||
|
||||
const primaryChildFragment = updateWorkInProgressOffscreenFiber(
|
||||
currentChild,
|
||||
offscreenChildProps,
|
||||
@@ -2534,17 +2515,6 @@ function updateSuspenseComponent(
|
||||
workInProgress.memoizedState = SUSPENDED_MARKER;
|
||||
return fallbackChildFragment;
|
||||
} else {
|
||||
if (
|
||||
prevState !== null &&
|
||||
includesOnlyRetries(renderLanes) &&
|
||||
includesSomeLane(renderLanes, current.lanes)
|
||||
) {
|
||||
// If we're rendering Retry lanes and we're entering the primary content then it's possible
|
||||
// that the only reason we rendered was because we left this boundary to be warmed up but
|
||||
// nothing else scheduled an update. If so, use it as the cause of the render.
|
||||
markRenderDerivedCause(workInProgress);
|
||||
}
|
||||
|
||||
pushPrimaryTreeSuspenseHandler(workInProgress);
|
||||
|
||||
const nextPrimaryChildren = nextProps.children;
|
||||
@@ -2903,13 +2873,6 @@ function updateDehydratedSuspenseComponent(
|
||||
// but after we've already committed once.
|
||||
warnIfHydrating();
|
||||
|
||||
if (includesSomeLane(renderLanes, (OffscreenLane: Lane))) {
|
||||
// If we're rendering Offscreen and we're entering the activity then it's possible
|
||||
// that the only reason we rendered was because this boundary left work. Provide
|
||||
// it as a cause if another one doesn't already exist.
|
||||
markRenderDerivedCause(workInProgress);
|
||||
}
|
||||
|
||||
if (isSuspenseInstanceFallback(suspenseInstance)) {
|
||||
// This boundary is in a permanent fallback state. In this case, we'll never
|
||||
// get an update and we'll never be able to hydrate the final content. Let's just try the
|
||||
|
||||
@@ -122,10 +122,7 @@ import {
|
||||
markStateUpdateScheduled,
|
||||
setIsStrictModeForDevtools,
|
||||
} from './ReactFiberDevToolsHook';
|
||||
import {
|
||||
startUpdateTimerByLane,
|
||||
startHostActionTimer,
|
||||
} from './ReactProfilerTimer';
|
||||
import {startUpdateTimerByLane} from './ReactProfilerTimer';
|
||||
import {createCache} from './ReactFiberCacheComponent';
|
||||
import {
|
||||
createUpdate as createLegacyQueueUpdate,
|
||||
@@ -3242,8 +3239,6 @@ export function startHostTransition<F>(
|
||||
BasicStateAction<Thenable<TransitionStatus> | TransitionStatus>,
|
||||
> = stateHook.queue;
|
||||
|
||||
startHostActionTimer(formFiber);
|
||||
|
||||
startTransition(
|
||||
formFiber,
|
||||
queue,
|
||||
|
||||
@@ -609,7 +609,6 @@ export function logBlockingStart(
|
||||
eventType: null | string,
|
||||
eventIsRepeat: boolean,
|
||||
isSpawnedUpdate: boolean,
|
||||
isPingedUpdate: boolean,
|
||||
renderStartTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask, // DEV-only
|
||||
@@ -659,13 +658,11 @@ export function logBlockingStart(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
isPingedUpdate
|
||||
? 'Promise Resolved'
|
||||
: isSpawnedUpdate
|
||||
? 'Cascading Update'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
isSpawnedUpdate
|
||||
? 'Cascading Update'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
updateTime,
|
||||
renderStartTime,
|
||||
currentTrack,
|
||||
@@ -675,13 +672,11 @@ export function logBlockingStart(
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
isPingedUpdate
|
||||
? 'Promise Resolved'
|
||||
: isSpawnedUpdate
|
||||
? 'Cascading Update'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
isSpawnedUpdate
|
||||
? 'Cascading Update'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
updateTime,
|
||||
renderStartTime,
|
||||
currentTrack,
|
||||
@@ -699,7 +694,6 @@ export function logTransitionStart(
|
||||
eventTime: number,
|
||||
eventType: null | string,
|
||||
eventIsRepeat: boolean,
|
||||
isPingedUpdate: boolean,
|
||||
renderStartTime: number,
|
||||
debugTask: null | ConsoleTask, // DEV-only
|
||||
): void {
|
||||
@@ -769,11 +763,7 @@ export function logTransitionStart(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
isPingedUpdate
|
||||
? 'Promise Resolved'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
renderStartTime - updateTime > 5 ? 'Update Blocked' : 'Update',
|
||||
updateTime,
|
||||
renderStartTime,
|
||||
currentTrack,
|
||||
@@ -783,11 +773,7 @@ export function logTransitionStart(
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
isPingedUpdate
|
||||
? 'Promise Resolved'
|
||||
: renderStartTime - updateTime > 5
|
||||
? 'Update Blocked'
|
||||
: 'Update',
|
||||
renderStartTime - updateTime > 5 ? 'Update Blocked' : 'Update',
|
||||
updateTime,
|
||||
renderStartTime,
|
||||
currentTrack,
|
||||
@@ -803,43 +789,23 @@ export function logRenderPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
const color = includesOnlyHydrationOrOffscreenLanes(lanes)
|
||||
? 'tertiary-dark'
|
||||
: 'primary-dark';
|
||||
const label = includesOnlyOffscreenLanes(lanes)
|
||||
? 'Prepared'
|
||||
: includesOnlyHydrationLanes(lanes)
|
||||
? 'Hydrated'
|
||||
: 'Render';
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
label,
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
label,
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
includesOnlyOffscreenLanes(lanes)
|
||||
? 'Prepared'
|
||||
: includesOnlyHydrationLanes(lanes)
|
||||
? 'Hydrated'
|
||||
: 'Render',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,43 +813,23 @@ export function logInterruptedRenderPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
const color = includesOnlyHydrationOrOffscreenLanes(lanes)
|
||||
? 'tertiary-dark'
|
||||
: 'primary-dark';
|
||||
const label = includesOnlyOffscreenLanes(lanes)
|
||||
? 'Prewarm'
|
||||
: includesOnlyHydrationLanes(lanes)
|
||||
? 'Interrupted Hydration'
|
||||
: 'Interrupted Render';
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
label,
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
label,
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
includesOnlyOffscreenLanes(lanes)
|
||||
? 'Prewarm'
|
||||
: includesOnlyHydrationLanes(lanes)
|
||||
? 'Interrupted Hydration'
|
||||
: 'Interrupted Render',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,38 +837,19 @@ export function logSuspendedRenderPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
const color = includesOnlyHydrationOrOffscreenLanes(lanes)
|
||||
? 'tertiary-dark'
|
||||
: 'primary-dark';
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Prewarm',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Prewarm',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Prewarm',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,39 +857,20 @@ export function logSuspendedWithDelayPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
// This means the render was suspended and cannot commit until it gets unblocked.
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
const color = includesOnlyHydrationOrOffscreenLanes(lanes)
|
||||
? 'tertiary-dark'
|
||||
: 'primary-dark';
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Suspended',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Suspended',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Suspended',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,12 +880,8 @@ export function logRecoveredRenderPhase(
|
||||
lanes: Lanes,
|
||||
recoverableErrors: Array<CapturedValue<mixed>>,
|
||||
hydrationFailed: boolean,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__) {
|
||||
const properties: Array<[string, string]> = [];
|
||||
for (let i = 0; i < recoverableErrors.length; i++) {
|
||||
@@ -993,7 +897,7 @@ export function logRecoveredRenderPhase(
|
||||
String(error);
|
||||
properties.push(['Recoverable Error', message]);
|
||||
}
|
||||
const options = {
|
||||
performance.measure('Recovered', {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
detail: {
|
||||
@@ -1007,15 +911,7 @@ export function logRecoveredRenderPhase(
|
||||
properties,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
performance.measure.bind(performance, 'Recovered', options),
|
||||
);
|
||||
} else {
|
||||
performance.measure('Recovered', options);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Recovered',
|
||||
@@ -1033,144 +929,68 @@ export function logErroredRenderPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
lanes: Lanes,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Errored',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Errored',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Errored',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function logInconsistentRender(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Teared Render',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Teared Render',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Teared Render',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'error',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function logSuspenseThrottlePhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
// This was inside a throttled Suspense boundary commit.
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Throttled',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Throttled',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Throttled',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function logSuspendedCommitPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
// This means the commit was suspended on CSS or images.
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
// TODO: Include the exact reason and URLs of what resources suspended.
|
||||
// TODO: This might also be Suspended while waiting on a View Transition.
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Suspended on CSS or Images',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Suspended on CSS or Images',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Suspended on CSS or Images',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,12 +999,8 @@ export function logCommitErrored(
|
||||
endTime: number,
|
||||
errors: Array<CapturedValue<mixed>>,
|
||||
passive: boolean,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__) {
|
||||
const properties: Array<[string, string]> = [];
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
@@ -1200,7 +1016,7 @@ export function logCommitErrored(
|
||||
String(error);
|
||||
properties.push(['Error', message]);
|
||||
}
|
||||
const options = {
|
||||
performance.measure('Errored', {
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
detail: {
|
||||
@@ -1214,15 +1030,7 @@ export function logCommitErrored(
|
||||
properties,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
performance.measure.bind(performance, 'Errored', options),
|
||||
);
|
||||
} else {
|
||||
performance.measure('Errored', options);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Errored',
|
||||
@@ -1240,39 +1048,20 @@ export function logCommitPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
errors: null | Array<CapturedValue<mixed>>,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (errors !== null) {
|
||||
logCommitErrored(startTime, endTime, errors, false, debugTask);
|
||||
logCommitErrored(startTime, endTime, errors, false);
|
||||
return;
|
||||
}
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Commit',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Commit',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Commit',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,35 +1069,16 @@ export function logPaintYieldPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
delayedUntilPaint: boolean,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
delayedUntilPaint ? 'Waiting for Paint' : '',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
delayedUntilPaint ? 'Waiting for Paint' : '',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
delayedUntilPaint ? 'Waiting for Paint' : '',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-light',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,38 +1086,19 @@ export function logPassiveCommitPhase(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
errors: null | Array<CapturedValue<mixed>>,
|
||||
debugTask: null | ConsoleTask,
|
||||
): void {
|
||||
if (errors !== null) {
|
||||
logCommitErrored(startTime, endTime, errors, true, debugTask);
|
||||
logCommitErrored(startTime, endTime, errors, true);
|
||||
return;
|
||||
}
|
||||
if (supportsUserTiming) {
|
||||
if (endTime <= startTime) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__ && debugTask) {
|
||||
debugTask.run(
|
||||
// $FlowFixMe[method-unbinding]
|
||||
console.timeStamp.bind(
|
||||
console,
|
||||
'Remaining Effects',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
console.timeStamp(
|
||||
'Remaining Effects',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
);
|
||||
}
|
||||
console.timeStamp(
|
||||
'Remaining Effects',
|
||||
startTime,
|
||||
endTime,
|
||||
currentTrack,
|
||||
LANES_TRACK_GROUP,
|
||||
'secondary-dark',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ export function createHydrationContainer(
|
||||
update.callback =
|
||||
callback !== undefined && callback !== null ? callback : null;
|
||||
enqueueUpdate(current, update, lane);
|
||||
startUpdateTimerByLane(lane, 'hydrateRoot()');
|
||||
scheduleInitialHydrationOnRoot(root, lane);
|
||||
|
||||
return root;
|
||||
|
||||
@@ -266,16 +266,15 @@ import {
|
||||
blockingClampTime,
|
||||
blockingUpdateTime,
|
||||
blockingUpdateTask,
|
||||
blockingUpdateType,
|
||||
blockingEventTime,
|
||||
blockingEventType,
|
||||
blockingEventIsRepeat,
|
||||
blockingSpawnedUpdate,
|
||||
blockingSuspendedTime,
|
||||
transitionClampTime,
|
||||
transitionStartTime,
|
||||
transitionUpdateTime,
|
||||
transitionUpdateTask,
|
||||
transitionUpdateType,
|
||||
transitionEventTime,
|
||||
transitionEventType,
|
||||
transitionEventIsRepeat,
|
||||
@@ -302,8 +301,6 @@ import {
|
||||
startPingTimerByLanes,
|
||||
recordEffectError,
|
||||
resetCommitErrors,
|
||||
PINGED_UPDATE,
|
||||
SPAWNED_UPDATE,
|
||||
} from './ReactProfilerTimer';
|
||||
|
||||
// DEV stuff
|
||||
@@ -485,9 +482,6 @@ export function getWorkInProgressTransitions(): null | Array<Transition> {
|
||||
return workInProgressTransitions;
|
||||
}
|
||||
|
||||
// The first setState call that eventually caused the current render.
|
||||
let workInProgressUpdateTask: null | ConsoleTask = null;
|
||||
|
||||
let currentPendingTransitionCallbacks: PendingTransitionCallbacks | null = null;
|
||||
let currentEndTime: number | null = null;
|
||||
|
||||
@@ -1110,11 +1104,7 @@ export function performWorkOnRoot(
|
||||
) {
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
setCurrentTrackFromLanes(lanes);
|
||||
logInconsistentRender(
|
||||
renderStartTime,
|
||||
renderEndTime,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logInconsistentRender(renderStartTime, renderEndTime);
|
||||
finalizeRender(lanes, renderEndTime);
|
||||
}
|
||||
// A store was mutated in an interleaved event. Render again,
|
||||
@@ -1140,12 +1130,7 @@ export function performWorkOnRoot(
|
||||
if (errorRetryLanes !== NoLanes) {
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
setCurrentTrackFromLanes(lanes);
|
||||
logErroredRenderPhase(
|
||||
renderStartTime,
|
||||
renderEndTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
|
||||
finalizeRender(lanes, renderEndTime);
|
||||
}
|
||||
lanes = errorRetryLanes;
|
||||
@@ -1176,12 +1161,7 @@ export function performWorkOnRoot(
|
||||
if (exitStatus === RootFatalErrored) {
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
setCurrentTrackFromLanes(lanes);
|
||||
logErroredRenderPhase(
|
||||
renderStartTime,
|
||||
renderEndTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logErroredRenderPhase(renderStartTime, renderEndTime, lanes);
|
||||
finalizeRender(lanes, renderEndTime);
|
||||
}
|
||||
prepareFreshStack(root, NoLanes);
|
||||
@@ -1322,12 +1302,7 @@ function finishConcurrentRender(
|
||||
// until we receive more data.
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
setCurrentTrackFromLanes(lanes);
|
||||
logSuspendedRenderPhase(
|
||||
renderStartTime,
|
||||
renderEndTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logSuspendedRenderPhase(renderStartTime, renderEndTime, lanes);
|
||||
finalizeRender(lanes, renderEndTime);
|
||||
trackSuspendedTime(lanes, renderEndTime);
|
||||
}
|
||||
@@ -1892,22 +1867,18 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
previousRenderStartTime,
|
||||
renderStartTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
} else {
|
||||
logInterruptedRenderPhase(
|
||||
previousRenderStartTime,
|
||||
renderStartTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
}
|
||||
finalizeRender(workInProgressRootRenderLanes, renderStartTime);
|
||||
}
|
||||
|
||||
workInProgressUpdateTask = null;
|
||||
if (includesSyncLane(lanes) || includesBlockingLane(lanes)) {
|
||||
workInProgressUpdateTask = blockingUpdateTask;
|
||||
const clampedUpdateTime =
|
||||
blockingUpdateTime >= 0 && blockingUpdateTime < blockingClampTime
|
||||
? blockingClampTime
|
||||
@@ -1927,7 +1898,6 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
? clampedUpdateTime
|
||||
: renderStartTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
}
|
||||
logBlockingStart(
|
||||
@@ -1935,8 +1905,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
clampedEventTime,
|
||||
blockingEventType,
|
||||
blockingEventIsRepeat,
|
||||
blockingUpdateType === SPAWNED_UPDATE,
|
||||
blockingUpdateType === PINGED_UPDATE,
|
||||
blockingSpawnedUpdate,
|
||||
renderStartTime,
|
||||
lanes,
|
||||
blockingUpdateTask,
|
||||
@@ -1944,7 +1913,6 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
clearBlockingTimers();
|
||||
}
|
||||
if (includesTransitionLane(lanes)) {
|
||||
workInProgressUpdateTask = transitionUpdateTask;
|
||||
const clampedStartTime =
|
||||
transitionStartTime >= 0 && transitionStartTime < transitionClampTime
|
||||
? transitionClampTime
|
||||
@@ -1968,7 +1936,6 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
? clampedUpdateTime
|
||||
: renderStartTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
}
|
||||
logTransitionStart(
|
||||
@@ -1977,7 +1944,6 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
|
||||
clampedEventTime,
|
||||
transitionEventType,
|
||||
transitionEventIsRepeat,
|
||||
transitionUpdateType === PINGED_UPDATE,
|
||||
renderStartTime,
|
||||
transitionUpdateTask,
|
||||
);
|
||||
@@ -2261,21 +2227,6 @@ function popAsyncDispatcher(prevAsyncDispatcher: any) {
|
||||
ReactSharedInternals.A = prevAsyncDispatcher;
|
||||
}
|
||||
|
||||
export function markRenderDerivedCause(fiber: Fiber): void {
|
||||
if (enableProfilerTimer && enableComponentPerformanceTrack) {
|
||||
if (__DEV__) {
|
||||
if (workInProgressUpdateTask === null) {
|
||||
// If we don't have a cause associated with this render, it's likely because some
|
||||
// other render left work behind on this Fiber. The real cause is this Fiber itself.
|
||||
// We use its debugTask as the cause for this render. This might not be the only
|
||||
// one when multiple siblings are rendered but they ideally shouldn't be.
|
||||
workInProgressUpdateTask =
|
||||
fiber._debugTask == null ? null : fiber._debugTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function markCommitTimeOfFallback() {
|
||||
globalMostRecentFallbackTime = now();
|
||||
}
|
||||
@@ -3288,7 +3239,6 @@ function commitRoot(
|
||||
completedRenderStartTime,
|
||||
completedRenderEndTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
} else if (recoverableErrors !== null) {
|
||||
const hydrationFailed =
|
||||
@@ -3302,15 +3252,9 @@ function commitRoot(
|
||||
lanes,
|
||||
recoverableErrors,
|
||||
hydrationFailed,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
} else {
|
||||
logRenderPhase(
|
||||
completedRenderStartTime,
|
||||
completedRenderEndTime,
|
||||
lanes,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logRenderPhase(completedRenderStartTime, completedRenderEndTime, lanes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3481,17 +3425,9 @@ function commitRoot(
|
||||
recordCommitTime();
|
||||
if (enableComponentPerformanceTrack) {
|
||||
if (suspendedCommitReason === SUSPENDED_COMMIT) {
|
||||
logSuspendedCommitPhase(
|
||||
completedRenderEndTime,
|
||||
commitStartTime,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logSuspendedCommitPhase(completedRenderEndTime, commitStartTime);
|
||||
} else if (suspendedCommitReason === THROTTLED_COMMIT) {
|
||||
logSuspenseThrottlePhase(
|
||||
completedRenderEndTime,
|
||||
commitStartTime,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
logSuspenseThrottlePhase(completedRenderEndTime, commitStartTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3736,7 +3672,6 @@ function flushSpawnedWork(): void {
|
||||
: commitStartTime,
|
||||
commitEndTime,
|
||||
commitErrors,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4212,7 +4147,6 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
|
||||
commitEndTime,
|
||||
passiveEffectStartTime,
|
||||
!!wasDelayedCommit,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4248,7 +4182,6 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
|
||||
passiveEffectStartTime,
|
||||
passiveEffectsEndTime,
|
||||
commitErrors,
|
||||
workInProgressUpdateTask,
|
||||
);
|
||||
finalizeRender(lanes, passiveEffectsEndTime);
|
||||
}
|
||||
|
||||
@@ -48,11 +48,6 @@ const createTask =
|
||||
console.createTask
|
||||
: (name: string) => null;
|
||||
|
||||
export const REGULAR_UPDATE: UpdateType = 0;
|
||||
export const SPAWNED_UPDATE: UpdateType = 1;
|
||||
export const PINGED_UPDATE: UpdateType = 2;
|
||||
export opaque type UpdateType = 0 | 1 | 2;
|
||||
|
||||
export let renderStartTime: number = -0;
|
||||
export let commitStartTime: number = -0;
|
||||
export let commitEndTime: number = -0;
|
||||
@@ -67,16 +62,15 @@ export let componentEffectErrors: null | Array<CapturedValue<mixed>> = null;
|
||||
export let blockingClampTime: number = -0;
|
||||
export let blockingUpdateTime: number = -1.1; // First sync setState scheduled.
|
||||
export let blockingUpdateTask: null | ConsoleTask = null; // First sync setState's stack trace.
|
||||
export let blockingUpdateType: UpdateType = 0;
|
||||
export let blockingEventTime: number = -1.1; // Event timeStamp of the first setState.
|
||||
export let blockingEventType: null | string = null; // Event type of the first setState.
|
||||
export let blockingEventIsRepeat: boolean = false;
|
||||
export let blockingSpawnedUpdate: boolean = false;
|
||||
export let blockingSuspendedTime: number = -1.1;
|
||||
// TODO: This should really be one per Transition lane.
|
||||
export let transitionClampTime: number = -0;
|
||||
export let transitionStartTime: number = -1.1; // First startTransition call before setState.
|
||||
export let transitionUpdateTime: number = -1.1; // First transition setState scheduled.
|
||||
export let transitionUpdateType: UpdateType = 0;
|
||||
export let transitionUpdateTask: null | ConsoleTask = null; // First transition setState's stack trace.
|
||||
export let transitionEventTime: number = -1.1; // Event timeStamp of the first transition.
|
||||
export let transitionEventType: null | string = null; // Event type of the first transition.
|
||||
@@ -103,7 +97,7 @@ export function startUpdateTimerByLane(lane: Lane, method: string): void {
|
||||
blockingUpdateTime = now();
|
||||
blockingUpdateTask = createTask(method);
|
||||
if (isAlreadyRendering()) {
|
||||
blockingUpdateType = SPAWNED_UPDATE;
|
||||
blockingSpawnedUpdate = true;
|
||||
}
|
||||
const newEventTime = resolveEventTimeStamp();
|
||||
const newEventType = resolveEventType();
|
||||
@@ -116,7 +110,7 @@ export function startUpdateTimerByLane(lane: Lane, method: string): void {
|
||||
// If this is a second update in the same event, we treat it as a spawned update.
|
||||
// This might be a microtask spawned from useEffect, multiple flushSync or
|
||||
// a setState in a microtask spawned after the first setState. Regardless it's bad.
|
||||
blockingUpdateType = SPAWNED_UPDATE;
|
||||
blockingSpawnedUpdate = true;
|
||||
}
|
||||
blockingEventTime = newEventTime;
|
||||
blockingEventType = newEventType;
|
||||
@@ -141,54 +135,6 @@ export function startUpdateTimerByLane(lane: Lane, method: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function startHostActionTimer(fiber: Fiber): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
// This schedules an update on both the blocking lane for the pending state and on the
|
||||
// transition lane for the action update. Using the debug task from the host fiber.
|
||||
if (blockingUpdateTime < 0) {
|
||||
blockingUpdateTime = now();
|
||||
blockingUpdateTask =
|
||||
__DEV__ && fiber._debugTask != null ? fiber._debugTask : null;
|
||||
if (isAlreadyRendering()) {
|
||||
blockingUpdateType = SPAWNED_UPDATE;
|
||||
}
|
||||
const newEventTime = resolveEventTimeStamp();
|
||||
const newEventType = resolveEventType();
|
||||
if (
|
||||
newEventTime !== blockingEventTime ||
|
||||
newEventType !== blockingEventType
|
||||
) {
|
||||
blockingEventIsRepeat = false;
|
||||
} else if (newEventType !== null) {
|
||||
// If this is a second update in the same event, we treat it as a spawned update.
|
||||
// This might be a microtask spawned from useEffect, multiple flushSync or
|
||||
// a setState in a microtask spawned after the first setState. Regardless it's bad.
|
||||
blockingUpdateType = SPAWNED_UPDATE;
|
||||
}
|
||||
blockingEventTime = newEventTime;
|
||||
blockingEventType = newEventType;
|
||||
}
|
||||
if (transitionUpdateTime < 0) {
|
||||
transitionUpdateTime = now();
|
||||
transitionUpdateTask =
|
||||
__DEV__ && fiber._debugTask != null ? fiber._debugTask : null;
|
||||
if (transitionStartTime < 0) {
|
||||
const newEventTime = resolveEventTimeStamp();
|
||||
const newEventType = resolveEventType();
|
||||
if (
|
||||
newEventTime !== transitionEventTime ||
|
||||
newEventType !== transitionEventType
|
||||
) {
|
||||
transitionEventIsRepeat = false;
|
||||
}
|
||||
transitionEventTime = newEventTime;
|
||||
transitionEventType = newEventType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function startPingTimerByLanes(lanes: Lanes): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
@@ -199,14 +145,10 @@ export function startPingTimerByLanes(lanes: Lanes): void {
|
||||
if (includesSyncLane(lanes) || includesBlockingLane(lanes)) {
|
||||
if (blockingUpdateTime < 0) {
|
||||
blockingClampTime = blockingUpdateTime = now();
|
||||
blockingUpdateTask = createTask('Promise Resolved');
|
||||
blockingUpdateType = PINGED_UPDATE;
|
||||
}
|
||||
} else if (includesTransitionLane(lanes)) {
|
||||
if (transitionUpdateTime < 0) {
|
||||
transitionClampTime = transitionUpdateTime = now();
|
||||
transitionUpdateTask = createTask('Promise Resolved');
|
||||
transitionUpdateType = PINGED_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,9 +166,10 @@ export function trackSuspendedTime(lanes: Lanes, renderEndTime: number) {
|
||||
|
||||
export function clearBlockingTimers(): void {
|
||||
blockingUpdateTime = -1.1;
|
||||
blockingUpdateType = 0;
|
||||
blockingUpdateTask = null;
|
||||
blockingSuspendedTime = -1.1;
|
||||
blockingEventIsRepeat = true;
|
||||
blockingSpawnedUpdate = false;
|
||||
}
|
||||
|
||||
export function startAsyncTransitionTimer(): void {
|
||||
@@ -253,6 +196,20 @@ export function hasScheduledTransitionWork(): boolean {
|
||||
return transitionUpdateTime > -1;
|
||||
}
|
||||
|
||||
// We use this marker to indicate that we have scheduled a render to be performed
|
||||
// but it's not an explicit state update.
|
||||
const ACTION_STATE_MARKER = -0.5;
|
||||
|
||||
export function startActionStateUpdate(): void {
|
||||
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
|
||||
return;
|
||||
}
|
||||
if (transitionUpdateTime < 0) {
|
||||
transitionUpdateTime = ACTION_STATE_MARKER;
|
||||
transitionUpdateTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearAsyncTransitionTimer(): void {
|
||||
transitionStartTime = -1.1;
|
||||
}
|
||||
@@ -260,7 +217,7 @@ export function clearAsyncTransitionTimer(): void {
|
||||
export function clearTransitionTimers(): void {
|
||||
transitionStartTime = -1.1;
|
||||
transitionUpdateTime = -1.1;
|
||||
transitionUpdateType = 0;
|
||||
transitionUpdateTask = null;
|
||||
transitionSuspendedTime = -1.1;
|
||||
transitionEventIsRepeat = true;
|
||||
}
|
||||
|
||||
13
packages/react-server/src/ReactFlightServer.js
vendored
13
packages/react-server/src/ReactFlightServer.js
vendored
@@ -4848,18 +4848,9 @@ function renderDebugModel(
|
||||
return existingReference;
|
||||
}
|
||||
|
||||
// $FlowFixMe[method-unbinding]
|
||||
const functionBody: string = Function.prototype.toString.call(value);
|
||||
|
||||
const name = value.name;
|
||||
const serializedValue = serializeEval(
|
||||
typeof name === 'string'
|
||||
? 'Object.defineProperty(' +
|
||||
functionBody +
|
||||
',"name",{value:' +
|
||||
JSON.stringify(name) +
|
||||
'})'
|
||||
: '(' + functionBody + ')',
|
||||
// $FlowFixMe[method-unbinding]
|
||||
'(' + Function.prototype.toString.call(value) + ')',
|
||||
);
|
||||
request.pendingDebugChunks++;
|
||||
const id = request.nextChunkId++;
|
||||
|
||||
Reference in New Issue
Block a user