Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cfde32738 |
@@ -1738,40 +1738,6 @@ export function isStableType(id: Identifier): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export function isStableTypeContainer(id: Identifier): boolean {
|
||||
const type_ = id.type;
|
||||
if (type_.kind !== 'Object') {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
isUseStateType(id) || // setState
|
||||
type_.shapeId === 'BuiltInUseActionState' || // setActionState
|
||||
isUseReducerType(id) || // dispatcher
|
||||
type_.shapeId === 'BuiltInUseTransition' // startTransition
|
||||
);
|
||||
}
|
||||
|
||||
export function evaluatesToStableTypeOrContainer(
|
||||
env: Environment,
|
||||
{value}: Instruction,
|
||||
): boolean {
|
||||
if (value.kind === 'CallExpression' || value.kind === 'MethodCall') {
|
||||
const callee =
|
||||
value.kind === 'CallExpression' ? value.callee : value.property;
|
||||
|
||||
const calleeHookKind = getHookKind(env, callee.identifier);
|
||||
switch (calleeHookKind) {
|
||||
case 'useState':
|
||||
case 'useReducer':
|
||||
case 'useActionState':
|
||||
case 'useRef':
|
||||
case 'useTransition':
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isUseEffectHookType(id: Identifier): boolean {
|
||||
return (
|
||||
id.type.kind === 'Function' && id.type.shapeId === 'BuiltInUseEffectHook'
|
||||
|
||||
@@ -9,19 +9,14 @@ import {CompilerError} from '..';
|
||||
import {
|
||||
BlockId,
|
||||
Effect,
|
||||
Environment,
|
||||
HIRFunction,
|
||||
Identifier,
|
||||
IdentifierId,
|
||||
Instruction,
|
||||
Place,
|
||||
computePostDominatorTree,
|
||||
evaluatesToStableTypeOrContainer,
|
||||
getHookKind,
|
||||
isStableType,
|
||||
isStableTypeContainer,
|
||||
isUseOperator,
|
||||
isUseRefType,
|
||||
} from '../HIR';
|
||||
import {PostDominator} from '../HIR/Dominator';
|
||||
import {
|
||||
@@ -36,103 +31,6 @@ import {
|
||||
import DisjointSet from '../Utils/DisjointSet';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
|
||||
/**
|
||||
* Side map to track and propagate sources of stability (i.e. hook calls such as
|
||||
* `useRef()` and property reads such as `useState()[1]). Note that this
|
||||
* requires forward data flow analysis since stability is not part of React
|
||||
* Compiler's type system.
|
||||
*/
|
||||
class StableSidemap {
|
||||
map: Map<IdentifierId, {isStable: boolean}> = new Map();
|
||||
env: Environment;
|
||||
|
||||
constructor(env: Environment) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
handleInstruction(instr: Instruction): void {
|
||||
const {value, lvalue} = instr;
|
||||
|
||||
switch (value.kind) {
|
||||
case 'CallExpression':
|
||||
case 'MethodCall': {
|
||||
/**
|
||||
* Sources of stability are known hook calls
|
||||
*/
|
||||
if (evaluatesToStableTypeOrContainer(this.env, instr)) {
|
||||
if (isStableType(lvalue.identifier)) {
|
||||
this.map.set(lvalue.identifier.id, {
|
||||
isStable: true,
|
||||
});
|
||||
} else {
|
||||
this.map.set(lvalue.identifier.id, {
|
||||
isStable: false,
|
||||
});
|
||||
}
|
||||
} else if (
|
||||
this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
|
||||
isUseRefType(lvalue.identifier)
|
||||
) {
|
||||
this.map.set(lvalue.identifier.id, {
|
||||
isStable: true,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Destructure':
|
||||
case 'PropertyLoad': {
|
||||
/**
|
||||
* PropertyLoads may from stable containers may also produce stable
|
||||
* values. ComputedLoads are technically safe for now (as all stable
|
||||
* containers have differently-typed elements), but are not handled as
|
||||
* they should be rare anyways.
|
||||
*/
|
||||
const source =
|
||||
value.kind === 'Destructure'
|
||||
? value.value.identifier.id
|
||||
: value.object.identifier.id;
|
||||
const entry = this.map.get(source);
|
||||
if (entry) {
|
||||
for (const lvalue of eachInstructionLValue(instr)) {
|
||||
if (isStableTypeContainer(lvalue.identifier)) {
|
||||
this.map.set(lvalue.identifier.id, {
|
||||
isStable: false,
|
||||
});
|
||||
} else if (isStableType(lvalue.identifier)) {
|
||||
this.map.set(lvalue.identifier.id, {
|
||||
isStable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'StoreLocal': {
|
||||
const entry = this.map.get(value.value.identifier.id);
|
||||
if (entry) {
|
||||
this.map.set(lvalue.identifier.id, entry);
|
||||
this.map.set(value.lvalue.place.identifier.id, entry);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'LoadLocal': {
|
||||
const entry = this.map.get(value.place.identifier.id);
|
||||
if (entry) {
|
||||
this.map.set(lvalue.identifier.id, entry);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isStable(id: IdentifierId): boolean {
|
||||
const entry = this.map.get(id);
|
||||
return entry != null ? entry.isStable : false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Infers which `Place`s are reactive, ie may *semantically* change
|
||||
* over the course of the component/hook's lifetime. Places are reactive
|
||||
@@ -213,7 +111,6 @@ class StableSidemap {
|
||||
*/
|
||||
export function inferReactivePlaces(fn: HIRFunction): void {
|
||||
const reactiveIdentifiers = new ReactivityMap(findDisjointMutableValues(fn));
|
||||
const stableIdentifierSources = new StableSidemap(fn.env);
|
||||
for (const param of fn.params) {
|
||||
const place = param.kind === 'Identifier' ? param : param.place;
|
||||
reactiveIdentifiers.markReactive(place);
|
||||
@@ -287,7 +184,6 @@ export function inferReactivePlaces(fn: HIRFunction): void {
|
||||
}
|
||||
}
|
||||
for (const instruction of block.instructions) {
|
||||
stableIdentifierSources.handleInstruction(instruction);
|
||||
const {value} = instruction;
|
||||
let hasReactiveInput = false;
|
||||
/*
|
||||
@@ -322,13 +218,7 @@ export function inferReactivePlaces(fn: HIRFunction): void {
|
||||
|
||||
if (hasReactiveInput) {
|
||||
for (const lvalue of eachInstructionLValue(instruction)) {
|
||||
/**
|
||||
* Note that it's not correct to mark all stable-typed identifiers
|
||||
* as non-reactive, since ternaries and other value blocks can
|
||||
* produce reactive identifiers typed as these.
|
||||
* (e.g. `props.cond ? setState1 : setState2`)
|
||||
*/
|
||||
if (stableIdentifierSources.isStable(lvalue.identifier.id)) {
|
||||
if (isStableType(lvalue.identifier)) {
|
||||
continue;
|
||||
}
|
||||
reactiveIdentifiers.markReactive(lvalue);
|
||||
|
||||
@@ -111,10 +111,7 @@ export default function inferReferenceEffects(
|
||||
* Initial state contains function params
|
||||
* TODO: include module declarations here as well
|
||||
*/
|
||||
const initialState = InferenceState.empty(
|
||||
fn.env,
|
||||
options.isFunctionExpression,
|
||||
);
|
||||
const initialState = InferenceState.empty(fn.env);
|
||||
const value: InstructionValue = {
|
||||
kind: 'Primitive',
|
||||
loc: fn.loc,
|
||||
@@ -258,7 +255,6 @@ type FreezeAction = {values: Set<InstructionValue>; reason: Set<ValueReason>};
|
||||
// Maintains a mapping of top-level variables to the kind of value they hold
|
||||
class InferenceState {
|
||||
env: Environment;
|
||||
#isFunctionExpression: boolean;
|
||||
|
||||
// The kind of each value, based on its allocation site
|
||||
#values: Map<InstructionValue, AbstractValue>;
|
||||
@@ -271,25 +267,16 @@ class InferenceState {
|
||||
|
||||
constructor(
|
||||
env: Environment,
|
||||
isFunctionExpression: boolean,
|
||||
values: Map<InstructionValue, AbstractValue>,
|
||||
variables: Map<IdentifierId, Set<InstructionValue>>,
|
||||
) {
|
||||
this.env = env;
|
||||
this.#isFunctionExpression = isFunctionExpression;
|
||||
this.#values = values;
|
||||
this.#variables = variables;
|
||||
}
|
||||
|
||||
static empty(
|
||||
env: Environment,
|
||||
isFunctionExpression: boolean,
|
||||
): InferenceState {
|
||||
return new InferenceState(env, isFunctionExpression, new Map(), new Map());
|
||||
}
|
||||
|
||||
get isFunctionExpression(): boolean {
|
||||
return this.#isFunctionExpression;
|
||||
static empty(env: Environment): InferenceState {
|
||||
return new InferenceState(env, new Map(), new Map());
|
||||
}
|
||||
|
||||
// (Re)initializes a @param value with its default @param kind.
|
||||
@@ -626,7 +613,6 @@ class InferenceState {
|
||||
} else {
|
||||
return new InferenceState(
|
||||
this.env,
|
||||
this.#isFunctionExpression,
|
||||
nextValues ?? new Map(this.#values),
|
||||
nextVariables ?? new Map(this.#variables),
|
||||
);
|
||||
@@ -641,7 +627,6 @@ class InferenceState {
|
||||
clone(): InferenceState {
|
||||
return new InferenceState(
|
||||
this.env,
|
||||
this.#isFunctionExpression,
|
||||
new Map(this.#values),
|
||||
new Map(this.#variables),
|
||||
);
|
||||
@@ -1796,15 +1781,8 @@ function inferBlock(
|
||||
if (block.terminal.kind === 'return' || block.terminal.kind === 'throw') {
|
||||
if (
|
||||
state.isDefined(operand) &&
|
||||
((operand.identifier.type.kind === 'Function' &&
|
||||
state.isFunctionExpression) ||
|
||||
state.kind(operand).kind === ValueKind.Context)
|
||||
state.kind(operand).kind === ValueKind.Context
|
||||
) {
|
||||
/**
|
||||
* Returned values should only be typed as 'frozen' if they are both (1)
|
||||
* local and (2) not a function expression which may capture and mutate
|
||||
* this function's outer context.
|
||||
*/
|
||||
effect = Effect.ConditionallyMutate;
|
||||
} else {
|
||||
effect = Effect.Freeze;
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @inferEffectDependencies
|
||||
import {useRef, useEffect} from 'react';
|
||||
import {print, mutate} from 'shared-runtime';
|
||||
|
||||
function Component({cond}) {
|
||||
const arr = useRef([]);
|
||||
const other = useRef([]);
|
||||
// Although arr and other are both stable, derived is not
|
||||
const derived = cond ? arr : other;
|
||||
useEffect(() => {
|
||||
mutate(derived.current);
|
||||
print(derived.current);
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
|
||||
import { useRef, useEffect } from "react";
|
||||
import { print, mutate } from "shared-runtime";
|
||||
|
||||
function Component(t0) {
|
||||
const $ = _c(4);
|
||||
const { cond } = t0;
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = [];
|
||||
$[0] = t1;
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
const arr = useRef(t1);
|
||||
let t2;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = [];
|
||||
$[1] = t2;
|
||||
} else {
|
||||
t2 = $[1];
|
||||
}
|
||||
const other = useRef(t2);
|
||||
|
||||
const derived = cond ? arr : other;
|
||||
let t3;
|
||||
if ($[2] !== derived) {
|
||||
t3 = () => {
|
||||
mutate(derived.current);
|
||||
print(derived.current);
|
||||
};
|
||||
$[2] = derived;
|
||||
$[3] = t3;
|
||||
} else {
|
||||
t3 = $[3];
|
||||
}
|
||||
useEffect(t3, [derived]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) Fixture not implemented
|
||||
@@ -1,15 +0,0 @@
|
||||
// @inferEffectDependencies
|
||||
import {useRef, useEffect} from 'react';
|
||||
import {print, mutate} from 'shared-runtime';
|
||||
|
||||
function Component({cond}) {
|
||||
const arr = useRef([]);
|
||||
const other = useRef([]);
|
||||
// Although arr and other are both stable, derived is not
|
||||
const derived = cond ? arr : other;
|
||||
useEffect(() => {
|
||||
mutate(derived.current);
|
||||
print(derived.current);
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
@@ -83,10 +83,10 @@ export const FIXTURE_ENTRYPOINT = {
|
||||
import { c as _c2 } from "react/compiler-runtime"; // @inlineJsxTransform
|
||||
|
||||
function Parent(t0) {
|
||||
const $ = _c2(3);
|
||||
const $ = _c2(2);
|
||||
const { children, ref } = t0;
|
||||
let t1;
|
||||
if ($[0] !== children || $[1] !== ref) {
|
||||
if ($[0] !== children) {
|
||||
if (DEV) {
|
||||
t1 = <div ref={ref}>{children}</div>;
|
||||
} else {
|
||||
@@ -99,10 +99,9 @@ function Parent(t0) {
|
||||
};
|
||||
}
|
||||
$[0] = children;
|
||||
$[1] = ref;
|
||||
$[2] = t1;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
*/
|
||||
function Foo({a, b}) {
|
||||
'use memo';
|
||||
const obj = {};
|
||||
const updaterFactory = () => {
|
||||
/**
|
||||
* This returned function expression *is* a local value. But it might (1)
|
||||
* capture and mutate its context environment and (2) be called during
|
||||
* render.
|
||||
* Typing it with `freeze` effects would be incorrect as it would mean
|
||||
* inferring that calls to updaterFactory()() do not mutate its captured
|
||||
* context.
|
||||
*/
|
||||
return newValue => {
|
||||
obj.value = newValue;
|
||||
obj.a = a;
|
||||
};
|
||||
};
|
||||
|
||||
const updater = updaterFactory();
|
||||
updater(b);
|
||||
return <Stringify cb={obj} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{a: 1, b: 2}],
|
||||
sequentialRenders: [
|
||||
{a: 1, b: 2},
|
||||
{a: 1, b: 3},
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { Stringify } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
*/
|
||||
function Foo(t0) {
|
||||
"use memo";
|
||||
const $ = _c(3);
|
||||
const { a, b } = t0;
|
||||
let t1;
|
||||
if ($[0] !== a || $[1] !== b) {
|
||||
const obj = {};
|
||||
const updaterFactory = () => (newValue) => {
|
||||
obj.value = newValue;
|
||||
obj.a = a;
|
||||
};
|
||||
|
||||
const updater = updaterFactory();
|
||||
updater(b);
|
||||
t1 = <Stringify cb={obj} shouldInvokeFns={true} />;
|
||||
$[0] = a;
|
||||
$[1] = b;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ a: 1, b: 2 }],
|
||||
sequentialRenders: [
|
||||
{ a: 1, b: 2 },
|
||||
{ a: 1, b: 3 },
|
||||
],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"cb":{"value":2,"a":1},"shouldInvokeFns":true}</div>
|
||||
<div>{"cb":{"value":3,"a":1},"shouldInvokeFns":true}</div>
|
||||
@@ -1,37 +0,0 @@
|
||||
import {Stringify} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
*/
|
||||
function Foo({a, b}) {
|
||||
'use memo';
|
||||
const obj = {};
|
||||
const updaterFactory = () => {
|
||||
/**
|
||||
* This returned function expression *is* a local value. But it might (1)
|
||||
* capture and mutate its context environment and (2) be called during
|
||||
* render.
|
||||
* Typing it with `freeze` effects would be incorrect as it would mean
|
||||
* inferring that calls to updaterFactory()() do not mutate its captured
|
||||
* context.
|
||||
*/
|
||||
return newValue => {
|
||||
obj.value = newValue;
|
||||
obj.a = a;
|
||||
};
|
||||
};
|
||||
|
||||
const updater = updaterFactory();
|
||||
updater(b);
|
||||
return <Stringify cb={obj} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{a: 1, b: 2}],
|
||||
sequentialRenders: [
|
||||
{a: 1, b: 2},
|
||||
{a: 1, b: 3},
|
||||
],
|
||||
};
|
||||
@@ -1,101 +0,0 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
import {makeArray, Stringify, useIdentity} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
* Also see repro-returned-inner-fn-mutates-context
|
||||
*/
|
||||
function Foo({b}) {
|
||||
'use memo';
|
||||
|
||||
const fnFactory = () => {
|
||||
/**
|
||||
* This returned function expression *is* a local value. But it might (1)
|
||||
* capture and mutate its context environment and (2) be called during
|
||||
* render.
|
||||
* Typing it with `freeze` effects would be incorrect as it would mean
|
||||
* inferring that calls to updaterFactory()() do not mutate its captured
|
||||
* context.
|
||||
*/
|
||||
return () => {
|
||||
myVar = () => console.log('a');
|
||||
};
|
||||
};
|
||||
let myVar = () => console.log('b');
|
||||
useIdentity();
|
||||
|
||||
const fn = fnFactory();
|
||||
const arr = makeArray(b);
|
||||
fn(arr);
|
||||
return <Stringify cb={myVar} value={arr} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{b: 1}],
|
||||
sequentialRenders: [{b: 1}, {b: 2}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime";
|
||||
import { makeArray, Stringify, useIdentity } from "shared-runtime";
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
* Also see repro-returned-inner-fn-mutates-context
|
||||
*/
|
||||
function Foo(t0) {
|
||||
"use memo";
|
||||
const $ = _c(3);
|
||||
const { b } = t0;
|
||||
|
||||
const fnFactory = () => () => {
|
||||
myVar = _temp;
|
||||
};
|
||||
|
||||
let myVar;
|
||||
myVar = _temp2;
|
||||
useIdentity();
|
||||
|
||||
const fn = fnFactory();
|
||||
const arr = makeArray(b);
|
||||
fn(arr);
|
||||
let t1;
|
||||
if ($[0] !== arr || $[1] !== myVar) {
|
||||
t1 = <Stringify cb={myVar} value={arr} shouldInvokeFns={true} />;
|
||||
$[0] = arr;
|
||||
$[1] = myVar;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
function _temp2() {
|
||||
return console.log("b");
|
||||
}
|
||||
function _temp() {
|
||||
return console.log("a");
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{ b: 1 }],
|
||||
sequentialRenders: [{ b: 1 }, { b: 2 }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) <div>{"cb":{"kind":"Function"},"value":[1],"shouldInvokeFns":true}</div>
|
||||
<div>{"cb":{"kind":"Function"},"value":[2],"shouldInvokeFns":true}</div>
|
||||
logs: ['a','a']
|
||||
@@ -1,37 +0,0 @@
|
||||
import {makeArray, Stringify, useIdentity} from 'shared-runtime';
|
||||
|
||||
/**
|
||||
* Example showing that returned inner function expressions should not be
|
||||
* typed with `freeze` effects.
|
||||
* Also see repro-returned-inner-fn-mutates-context
|
||||
*/
|
||||
function Foo({b}) {
|
||||
'use memo';
|
||||
|
||||
const fnFactory = () => {
|
||||
/**
|
||||
* This returned function expression *is* a local value. But it might (1)
|
||||
* capture and mutate its context environment and (2) be called during
|
||||
* render.
|
||||
* Typing it with `freeze` effects would be incorrect as it would mean
|
||||
* inferring that calls to updaterFactory()() do not mutate its captured
|
||||
* context.
|
||||
*/
|
||||
return () => {
|
||||
myVar = () => console.log('a');
|
||||
};
|
||||
};
|
||||
let myVar = () => console.log('b');
|
||||
useIdentity();
|
||||
|
||||
const fn = fnFactory();
|
||||
const arr = makeArray(b);
|
||||
fn(arr);
|
||||
return <Stringify cb={myVar} value={arr} shouldInvokeFns={true} />;
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Foo,
|
||||
params: [{b: 1}],
|
||||
sequentialRenders: [{b: 1}, {b: 2}],
|
||||
};
|
||||
@@ -4,8 +4,6 @@ import Theme, {ThemeToggleButton} from './Theme';
|
||||
|
||||
import './Chrome.css';
|
||||
|
||||
import LargeContent from './LargeContent';
|
||||
|
||||
export default class Chrome extends Component {
|
||||
state = {theme: 'light'};
|
||||
render() {
|
||||
@@ -27,6 +25,7 @@ export default class Chrome extends Component {
|
||||
/>
|
||||
<Suspense fallback="Loading...">
|
||||
<Theme.Provider value={this.state.theme}>
|
||||
{this.props.children}
|
||||
<div>
|
||||
<ThemeToggleButton
|
||||
onChange={theme => {
|
||||
@@ -36,14 +35,9 @@ export default class Chrome extends Component {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{this.props.children}
|
||||
</Theme.Provider>
|
||||
</Suspense>
|
||||
<p>This should appear in the first paint.</p>
|
||||
<Suspense fallback="Loading...">
|
||||
<p>This content should not block paint.</p>
|
||||
<LargeContent />
|
||||
</Suspense>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `assetManifest = ${JSON.stringify(assets)};`,
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
import React, {Fragment} from 'react';
|
||||
|
||||
export default function LargeContent() {
|
||||
return (
|
||||
<Fragment>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris
|
||||
porttitor tortor ac lectus faucibus, eget eleifend elit hendrerit.
|
||||
Integer porttitor nisi in leo congue rutrum. Morbi sed ante posuere,
|
||||
aliquam lorem ac, imperdiet orci. Duis malesuada gravida pharetra. Cras
|
||||
facilisis arcu diam, id dictum lorem imperdiet a. Suspendisse aliquet
|
||||
tempus tortor et ultricies. Aliquam libero velit, posuere tempus ante
|
||||
sed, pellentesque tincidunt lorem. Nullam iaculis, eros a varius
|
||||
aliquet, tortor felis tempor metus, nec cursus felis eros aliquam nulla.
|
||||
Vivamus ut orci sed mauris congue lacinia. Cras eget blandit neque.
|
||||
Pellentesque a massa in turpis ullamcorper volutpat vel at massa. Sed
|
||||
ante est, auctor non diam non, vulputate ultrices metus. Maecenas dictum
|
||||
fermentum quam id aliquam. Donec porta risus vitae pretium posuere.
|
||||
Fusce facilisis eros in lacus tincidunt congue.
|
||||
</p>
|
||||
<p>
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada
|
||||
fames ac turpis egestas. Phasellus dolor ante, iaculis vel nisl vitae,
|
||||
ornare ornare orci. Praesent sit amet lobortis sapien. Suspendisse
|
||||
pharetra posuere libero ut dapibus. Donec condimentum ante urna. Aliquam
|
||||
laoreet tincidunt lacus, sed interdum tortor dapibus elementum. Nam sed
|
||||
faucibus lorem. Suspendisse finibus, velit sed molestie finibus, risus
|
||||
purus mollis ante, sit amet aliquet sapien nulla ut nibh. In eget ligula
|
||||
metus. Duis in purus mattis, blandit magna nec, dictum nunc.
|
||||
</p>
|
||||
<p>
|
||||
Sed convallis magna id tortor blandit dictum. Suspendisse in porttitor
|
||||
neque. Integer quis metus consequat, rutrum est sit amet, finibus justo.
|
||||
In hac habitasse platea dictumst. Nullam sagittis, risus sed vehicula
|
||||
porta, sapien elit ultrices nibh, vel luctus odio tortor et ante. Sed
|
||||
porta enim in hendrerit tristique. Pellentesque id feugiat libero, sit
|
||||
amet tempor enim. Proin gravida nisl justo, vel ornare dolor bibendum
|
||||
ac. Mauris scelerisque mattis facilisis. Praesent sodales augue mollis
|
||||
orci vulputate aliquet. Mauris molestie luctus neque, sed congue elit
|
||||
congue ut. Cras quis tortor augue. In auctor nulla vel turpis dapibus
|
||||
egestas. Phasellus consequat rhoncus nisi sed dignissim. Quisque varius
|
||||
justo non ex lobortis finibus cursus nec justo. Nulla erat neque,
|
||||
commodo et sem convallis, tristique faucibus odio.
|
||||
</p>
|
||||
<p>
|
||||
Ut condimentum volutpat sem, id accumsan augue placerat vel. Donec ac
|
||||
efficitur turpis. Suspendisse pretium odio euismod sapien bibendum, sed
|
||||
tempus est condimentum. Etiam nisl magna, consequat at ullamcorper at,
|
||||
sollicitudin eu eros. In mattis ligula arcu. Sed eu consectetur turpis,
|
||||
id molestie ligula. Vestibulum et venenatis enim. Donec condimentum
|
||||
vitae nisi et placerat. Sed fringilla vehicula egestas. Proin
|
||||
consectetur, nibh non ornare scelerisque, diam lorem cursus lectus, ut
|
||||
mattis mauris purus id mi. Curabitur non ligula sit amet augue molestie
|
||||
vulputate. Donec maximus magna at volutpat aliquet. Pellentesque
|
||||
dignissim nulla eget odio eleifend tincidunt. Etiam diam lorem, ornare
|
||||
vel scelerisque vel, iaculis id risus. Donec aliquet aliquam felis, ac
|
||||
vehicula lacus suscipit vitae. Morbi eu ligula elit.
|
||||
</p>
|
||||
<p>
|
||||
Praesent pellentesque, libero ut faucibus tempor, purus elit consequat
|
||||
metus, in ornare nulla lectus at erat. Duis quis blandit turpis. Fusce
|
||||
at ligula rutrum metus molestie tempor sit amet eu justo. Maecenas
|
||||
tincidunt nisl nunc. Morbi ac metus tempor, pretium arcu vel, dapibus
|
||||
velit. Nulla convallis ligula at porta mollis. Duis magna ante, mollis
|
||||
eget nibh in, congue tempor dolor. Sed tincidunt sagittis arcu, in
|
||||
ultricies neque tempor non. Suspendisse eget nunc neque. Nulla sit amet
|
||||
odio volutpat, maximus purus id, dictum metus. Integer consequat, orci
|
||||
nec ullamcorper porta, mauris libero vestibulum ipsum, nec tempor tellus
|
||||
enim non nunc. Quisque nisl risus, dapibus sit amet purus nec, aliquam
|
||||
finibus metus. Nullam condimentum urna viverra finibus cursus. Proin et
|
||||
sollicitudin tellus, porta fermentum felis. Maecenas ac turpis sed dui
|
||||
condimentum interdum sed sed erat. Mauris ut dignissim erat.
|
||||
</p>
|
||||
<p>
|
||||
Proin varius porta dui, id fringilla elit lobortis eget. Integer at
|
||||
metus elementum, efficitur eros id, euismod est. Morbi vestibulum nibh
|
||||
ac leo luctus sagittis. Praesent rhoncus, risus sit amet mattis dictum,
|
||||
diam sapien tempor neque, vel dignissim nulla neque eget ex. Nam
|
||||
sollicitudin metus quis ullamcorper dapibus. Nam tristique euismod
|
||||
efficitur. Pellentesque rhoncus vel sem eget lacinia. Pellentesque
|
||||
volutpat velit ac dignissim luctus. Vivamus euismod tortor at ligula
|
||||
mattis porta. Vestibulum ante ipsum primis in faucibus orci luctus et
|
||||
ultrices posuere cubilia curae;
|
||||
</p>
|
||||
<p>
|
||||
Proin blandit vulputate efficitur. Pellentesque sit amet porta odio.
|
||||
Nunc pulvinar varius rhoncus. Mauris fermentum leo a imperdiet pretium.
|
||||
Mauris scelerisque justo vel ante egestas, eget tempus neque malesuada.
|
||||
Sed dictum ex vel justo dignissim, aliquam commodo diam rutrum. Integer
|
||||
dignissim est ullamcorper augue laoreet consectetur id at diam. Vivamus
|
||||
molestie blandit urna, eget pulvinar augue dictum vestibulum. Duis
|
||||
maximus bibendum mauris, ut ultricies elit rhoncus eu. Praesent gravida
|
||||
placerat mauris. Praesent tempor ipsum at nibh rhoncus sagittis. Duis
|
||||
non sem turpis. Quisque et metus leo. Sed eu purus lorem. Pellentesque
|
||||
dictum metus sed leo viverra interdum. Maecenas vel tincidunt mi.
|
||||
</p>
|
||||
<p>
|
||||
Praesent consequat dapibus pellentesque. Fusce at enim id mauris laoreet
|
||||
commodo. Nullam ut mauris euismod, rhoncus tellus vel, facilisis diam.
|
||||
Aenean porta faucibus augue, a iaculis massa iaculis in. Praesent vel
|
||||
metus purus. Etiam quis augue eget orci lobortis eleifend ac ut lorem.
|
||||
Aenean non orci quis nisi molestie maximus. Mauris interdum, eros et
|
||||
aliquam aliquam, lectus diam pharetra velit, in condimentum odio eros
|
||||
non quam. Praesent bibendum pretium turpis vitae tristique. Mauris
|
||||
convallis, massa ut fermentum fermentum, libero orci tempus ipsum,
|
||||
malesuada ultrices metus sapien placerat lectus. Ut fringilla arcu nec
|
||||
lorem ultrices mattis. Etiam id tortor feugiat magna gravida gravida.
|
||||
Morbi aliquam, mi ac pellentesque mattis, erat ex venenatis erat, a
|
||||
vestibulum eros turpis quis metus. Pellentesque tempus justo in ligula
|
||||
ultricies porta. Phasellus congue felis sit amet dolor tristique
|
||||
finibus. Nunc eget eros non est ultricies vestibulum.
|
||||
</p>
|
||||
<p>
|
||||
Donec efficitur ligula quis odio tincidunt tristique. Duis urna dolor,
|
||||
hendrerit quis enim at, accumsan auctor turpis. Vivamus ante lorem,
|
||||
maximus vitae suscipit ut, congue eget velit. Maecenas sed ligula erat.
|
||||
Aliquam mollis purus at nisi porta suscipit in ut magna. Vivamus a
|
||||
turpis nec tellus egestas suscipit nec ornare nisi. Donec vestibulum
|
||||
libero quis ex suscipit, sit amet luctus leo gravida.
|
||||
</p>
|
||||
<p>
|
||||
Praesent pharetra dolor elit, sed volutpat lorem rhoncus non. Etiam a
|
||||
neque ut velit dignissim sodales. Vestibulum neque risus, condimentum
|
||||
nec consectetur vitae, ultricies ut sapien. Integer iaculis at urna sit
|
||||
amet malesuada. Integer tincidunt, felis ac vulputate semper, velit leo
|
||||
facilisis lorem, quis aliquet leo dui id lorem. Morbi non quam quis nisl
|
||||
sagittis consequat nec vitae libero. Nunc molestie pretium libero, eu
|
||||
eleifend nibh feugiat sed. Ut in bibendum diam, sit amet vehicula risus.
|
||||
Nam ornare ac nisi ac euismod. Nullam id egestas nulla. Etiam porta
|
||||
commodo ante sit amet pellentesque. Suspendisse eleifend purus in urna
|
||||
euismod auctor non vel nisi. Suspendisse rutrum est nunc, sit amet
|
||||
lacinia lacus dictum eget. Pellentesque habitant morbi tristique
|
||||
senectus et netus et malesuada fames ac turpis egestas. Morbi a blandit
|
||||
diam.
|
||||
</p>
|
||||
<p>
|
||||
Donec eget efficitur sapien. Suspendisse diam lacus, varius eu interdum
|
||||
et, congue ac justo. Proin ipsum odio, suscipit elementum mauris sed,
|
||||
porttitor congue est. Cras dapibus dictum ante, vitae gravida elit
|
||||
venenatis sed. Sed massa sem, posuere ut enim sit amet, vestibulum
|
||||
condimentum nibh. Pellentesque pulvinar sodales lacinia. Proin id
|
||||
pretium sapien, non convallis nulla. In mollis tincidunt sem et
|
||||
porttitor.
|
||||
</p>
|
||||
<p>
|
||||
Integer at sollicitudin sem. Suspendisse sed semper orci. Nulla at nibh
|
||||
nec risus suscipit posuere egestas vitae enim. Nullam mauris justo,
|
||||
mattis vel laoreet non, finibus nec nisl. Cras iaculis ultrices nibh,
|
||||
non commodo eros aliquam non. Sed vitae mollis dui, at maximus metus. Ut
|
||||
vestibulum, enim ut lobortis vulputate, lorem urna congue elit, non
|
||||
dictum odio lorem eget velit. Morbi eleifend id ligula vitae vulputate.
|
||||
Suspendisse ac laoreet justo. Proin eu mattis diam.
|
||||
</p>
|
||||
<p>
|
||||
Nunc in ex quis enim ullamcorper scelerisque eget ac eros. Class aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||
himenaeos. Aliquam turpis dui, egestas a rhoncus non, fermentum in
|
||||
tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices
|
||||
posuere cubilia curae; Aenean non risus arcu. Nam ultricies lacinia
|
||||
volutpat. Class aptent taciti sociosqu ad litora torquent per conubia
|
||||
nostra, per inceptos himenaeos. Lorem ipsum dolor sit amet, consectetur
|
||||
adipiscing elit.
|
||||
</p>
|
||||
<p>
|
||||
Aliquam a felis leo. Proin lorem ipsum, congue eu cursus in, rhoncus ut
|
||||
libero. Vestibulum sit amet consequat nunc. Ut eleifend lobortis lacus,
|
||||
vel molestie metus viverra eget. Nullam suscipit eu magna scelerisque
|
||||
suscipit. Donec dictum in diam nec lacinia. Mauris pellentesque ex ut
|
||||
purus facilisis, eget placerat turpis semper. Sed dapibus lorem ante, et
|
||||
malesuada dui eleifend ac. Sed diam felis, semper ac nulla vel, posuere
|
||||
ultricies ante.
|
||||
</p>
|
||||
<p>
|
||||
Nunc elementum odio sapien, sit amet vulputate lorem varius at. Fusce
|
||||
non sapien vitae lorem aliquam pretium sit amet congue dolor. Nunc quis
|
||||
tortor luctus, pretium ex a, tincidunt urna. Aliquam fermentum massa a
|
||||
erat pharetra varius. Curabitur at auctor dui. Sed posuere pellentesque
|
||||
massa, vel bibendum urna dictum non. Fusce eget rhoncus urna. Maecenas
|
||||
sed lectus tellus. Pellentesque convallis dapibus nisl vitae venenatis.
|
||||
Quisque ornare a dolor ac pharetra. Nam cursus, mi a lacinia accumsan,
|
||||
felis erat fringilla magna, ac mattis nunc ante a orci.
|
||||
</p>
|
||||
<p>
|
||||
Nunc vel tortor euismod, commodo tortor non, aliquam nisi. Maecenas
|
||||
tempus mollis velit non suscipit. Mauris sit amet dolor sed ex fringilla
|
||||
varius. Suspendisse vel cursus risus. Vivamus pharetra massa nec dolor
|
||||
aliquam feugiat. Fusce finibus enim commodo, scelerisque ante eu,
|
||||
laoreet ex. Curabitur placerat magna quis imperdiet lacinia. Etiam
|
||||
lectus mauris, porttitor ac lacinia sed, posuere eget lacus. Mauris
|
||||
vulputate mattis imperdiet. Nunc id aliquet libero, vitae hendrerit
|
||||
purus. Praesent vestibulum urna ac egestas tempor. In molestie, nunc sit
|
||||
amet sagittis dapibus, ligula enim fermentum mi, lacinia molestie eros
|
||||
dui in tortor. Mauris fermentum pulvinar faucibus. Curabitur laoreet
|
||||
eleifend purus, non tincidunt tortor gravida nec. Nam eu lectus congue,
|
||||
commodo libero et, porttitor est. Nullam tincidunt, nisi eu congue
|
||||
congue, magna justo commodo massa, nec efficitur dui lectus non sem.
|
||||
</p>
|
||||
<p>
|
||||
Nullam vehicula, ipsum quis lacinia tristique, elit nulla dignissim
|
||||
augue, at pulvinar metus justo ac magna. Nullam nec nunc ac sapien
|
||||
mollis cursus eu ac enim. Pellentesque a pharetra erat. Ut tempor magna
|
||||
nisi, accumsan blandit lectus volutpat nec. Vivamus vel lorem nec eros
|
||||
blandit dictum eget ac diam. Nulla nec turpis dolor. Morbi eu euismod
|
||||
libero. Nam ut tortor at arcu porta tincidunt. In gravida ligula
|
||||
fringilla ornare imperdiet. Nulla scelerisque ante erat, efficitur
|
||||
dictum metus ullamcorper vel. Nam ac purus metus. Maecenas eget tempus
|
||||
nulla. Ut magna lorem, efficitur ut ex a, semper aliquam magna. Praesent
|
||||
lobortis, velit ac posuere mattis, justo est accumsan turpis, id
|
||||
sagittis felis mi in lacus.
|
||||
</p>
|
||||
<p>
|
||||
Aenean est mi, semper nec sem at, malesuada consectetur nunc. Aenean
|
||||
consequat sem quis sem consequat, non aliquam est placerat. Cras
|
||||
malesuada magna neque, et pellentesque nibh consequat at. Sed interdum
|
||||
velit et ex interdum, vel lobortis ante vestibulum. Nam placerat lectus
|
||||
eu commodo efficitur. Pellentesque in nunc ac massa porttitor eleifend
|
||||
ut efficitur sem. Aenean at magna auctor, posuere augue in, ultrices
|
||||
arcu. Praesent dignissim augue ex, malesuada maximus metus interdum a.
|
||||
Proin nec odio in nulla vestibulum.
|
||||
</p>
|
||||
<p>
|
||||
Aenean est mi, semper nec sem at, malesuada consectetur nunc. Aenean
|
||||
consequat sem quis sem consequat, non aliquam est placerat. Cras
|
||||
malesuada magna neque, et pellentesque nibh consequat at. Sed interdum
|
||||
velit et ex interdum, vel lobortis ante vestibulum. Nam placerat lectus
|
||||
eu commodo efficitur. Pellentesque in nunc ac massa porttitor eleifend
|
||||
ut efficitur sem. Aenean at magna auctor, posuere augue in, ultrices
|
||||
arcu. Praesent dignissim augue ex, malesuada maximus metus interdum a.
|
||||
Proin nec odio in nulla vestibulum.
|
||||
</p>
|
||||
<p>
|
||||
Aenean est mi, semper nec sem at, malesuada consectetur nunc. Aenean
|
||||
consequat sem quis sem consequat, non aliquam est placerat. Cras
|
||||
malesuada magna neque, et pellentesque nibh consequat at. Sed interdum
|
||||
velit et ex interdum, vel lobortis ante vestibulum. Nam placerat lectus
|
||||
eu commodo efficitur. Pellentesque in nunc ac massa porttitor eleifend
|
||||
ut efficitur sem. Aenean at magna auctor, posuere augue in, ultrices
|
||||
arcu. Praesent dignissim augue ex, malesuada maximus metus interdum a.
|
||||
Proin nec odio in nulla vestibulum.
|
||||
</p>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
@@ -906,8 +906,8 @@ describe('InspectedElement', () => {
|
||||
},
|
||||
"usedRejectedPromise": {
|
||||
"reason": Dehydrated {
|
||||
"preview_short": Error: test-error-do-not-surface,
|
||||
"preview_long": Error: test-error-do-not-surface,
|
||||
"preview_short": Error,
|
||||
"preview_long": Error,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
64
packages/react-devtools-shared/src/hydration.js
vendored
64
packages/react-devtools-shared/src/hydration.js
vendored
@@ -397,7 +397,7 @@ export function dehydrate(
|
||||
return object;
|
||||
}
|
||||
|
||||
case 'class_instance': {
|
||||
case 'class_instance':
|
||||
isPathAllowedCheck = isPathAllowed(path);
|
||||
|
||||
if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
|
||||
@@ -433,69 +433,7 @@ export function dehydrate(
|
||||
unserializable.push(path);
|
||||
|
||||
return value;
|
||||
}
|
||||
case 'error': {
|
||||
isPathAllowedCheck = isPathAllowed(path);
|
||||
|
||||
if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) {
|
||||
return createDehydrated(type, true, data, cleaned, path);
|
||||
}
|
||||
|
||||
const value: Unserializable = {
|
||||
unserializable: true,
|
||||
type,
|
||||
readonly: true,
|
||||
preview_short: formatDataForPreview(data, false),
|
||||
preview_long: formatDataForPreview(data, true),
|
||||
name: data.name,
|
||||
};
|
||||
|
||||
// name, message, stack and cause are not enumerable yet still interesting.
|
||||
value.message = dehydrate(
|
||||
data.message,
|
||||
cleaned,
|
||||
unserializable,
|
||||
path.concat(['message']),
|
||||
isPathAllowed,
|
||||
isPathAllowedCheck ? 1 : level + 1,
|
||||
);
|
||||
value.stack = dehydrate(
|
||||
data.stack,
|
||||
cleaned,
|
||||
unserializable,
|
||||
path.concat(['stack']),
|
||||
isPathAllowed,
|
||||
isPathAllowedCheck ? 1 : level + 1,
|
||||
);
|
||||
|
||||
if ('cause' in data) {
|
||||
value.cause = dehydrate(
|
||||
data.cause,
|
||||
cleaned,
|
||||
unserializable,
|
||||
path.concat(['cause']),
|
||||
isPathAllowed,
|
||||
isPathAllowedCheck ? 1 : level + 1,
|
||||
);
|
||||
}
|
||||
|
||||
getAllEnumerableKeys(data).forEach(key => {
|
||||
const keyAsString = key.toString();
|
||||
|
||||
value[keyAsString] = dehydrate(
|
||||
data[key],
|
||||
cleaned,
|
||||
unserializable,
|
||||
path.concat([keyAsString]),
|
||||
isPathAllowed,
|
||||
isPathAllowedCheck ? 1 : level + 1,
|
||||
);
|
||||
});
|
||||
|
||||
unserializable.push(path);
|
||||
|
||||
return value;
|
||||
}
|
||||
case 'infinity':
|
||||
case 'nan':
|
||||
case 'undefined':
|
||||
|
||||
20
packages/react-devtools-shared/src/utils.js
vendored
20
packages/react-devtools-shared/src/utils.js
vendored
@@ -554,7 +554,6 @@ export type DataType =
|
||||
| 'class_instance'
|
||||
| 'data_view'
|
||||
| 'date'
|
||||
| 'error'
|
||||
| 'function'
|
||||
| 'html_all_collection'
|
||||
| 'html_element'
|
||||
@@ -574,21 +573,6 @@ export type DataType =
|
||||
| 'undefined'
|
||||
| 'unknown';
|
||||
|
||||
function isError(data: Object): boolean {
|
||||
// If it doesn't event look like an error, it won't be an actual error.
|
||||
if ('name' in data && 'message' in data) {
|
||||
while (data) {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
if (Object.prototype.toString.call(data) === '[object Error]') {
|
||||
return true;
|
||||
}
|
||||
data = Object.getPrototypeOf(data);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a enhanced/artificial type string based on the object instance
|
||||
*/
|
||||
@@ -650,8 +634,6 @@ export function getDataType(data: Object): DataType {
|
||||
return 'regexp';
|
||||
} else if (typeof data.then === 'function') {
|
||||
return 'thenable';
|
||||
} else if (isError(data)) {
|
||||
return 'error';
|
||||
} else {
|
||||
// $FlowFixMe[method-unbinding]
|
||||
const toStringValue = Object.prototype.toString.call(data);
|
||||
@@ -1014,8 +996,6 @@ export function formatDataForPreview(
|
||||
} else {
|
||||
return '{…}';
|
||||
}
|
||||
case 'error':
|
||||
return truncateForDisplay(String(data));
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
case 'infinity':
|
||||
|
||||
@@ -130,14 +130,6 @@ const usedRejectedPromise = Promise.reject(
|
||||
new Error('test-error-do-not-surface'),
|
||||
);
|
||||
|
||||
class DigestError extends Error {
|
||||
digest: string;
|
||||
constructor(message: string, options: any, digest: string) {
|
||||
super(message, options);
|
||||
this.digest = digest;
|
||||
}
|
||||
}
|
||||
|
||||
export default function Hydration(): React.Node {
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -157,13 +149,6 @@ export default function Hydration(): React.Node {
|
||||
usedFulfilledRichPromise={usedFulfilledRichPromise}
|
||||
usedPendingPromise={usedPendingPromise}
|
||||
usedRejectedPromise={usedRejectedPromise}
|
||||
// eslint-disable-next-line react-internal/prod-error-codes
|
||||
error={new Error('test')}
|
||||
// eslint-disable-next-line react-internal/prod-error-codes
|
||||
errorWithCause={new Error('one', {cause: new TypeError('two')})}
|
||||
errorWithDigest={new DigestError('test', {}, 'some-digest')}
|
||||
// $FlowFixMe[cannot-resolve-name] Flow doesn't know about DOMException
|
||||
domexception={new DOMException('test')}
|
||||
/>
|
||||
<DeepHooks />
|
||||
</Fragment>
|
||||
|
||||
@@ -695,7 +695,6 @@ export function resetResumableState(
|
||||
resumableState.scriptResources = {};
|
||||
resumableState.moduleUnknownResources = {};
|
||||
resumableState.moduleScriptResources = {};
|
||||
resumableState.instructions = NothingSent; // Nothing was flushed so no instructions could've flushed.
|
||||
}
|
||||
|
||||
export function completeResumableState(resumableState: ResumableState): void {
|
||||
|
||||
@@ -98,8 +98,6 @@ const ReactNoopServer = ReactFizzServer({
|
||||
closeWithError(destination: Destination, error: mixed): void {},
|
||||
flushBuffered(destination: Destination): void {},
|
||||
|
||||
byteLengthOfChunk: null,
|
||||
|
||||
getChildFormatContext(): null {
|
||||
return null;
|
||||
},
|
||||
|
||||
66
packages/react-server/src/ReactFizzServer.js
vendored
66
packages/react-server/src/ReactFizzServer.js
vendored
@@ -50,7 +50,6 @@ import {
|
||||
flushBuffered,
|
||||
close,
|
||||
closeWithError,
|
||||
byteLengthOfChunk,
|
||||
} from './ReactServerStreamConfig';
|
||||
import {
|
||||
writeCompletedRoot,
|
||||
@@ -349,7 +348,6 @@ export opaque type Request = {
|
||||
pendingRootTasks: number, // when this reaches zero, we've finished at least the root boundary.
|
||||
completedRootSegment: null | Segment, // Completed but not yet flushed root segments.
|
||||
completedPreambleSegments: null | Array<Array<Segment>>, // contains the ready-to-flush segments that make up the preamble
|
||||
byteSize: number, // counts the number of bytes accumulated in the shell
|
||||
abortableTasks: Set<Task>,
|
||||
pingedTasks: Array<Task>, // High priority tasks that should be worked on first.
|
||||
// Queues to flush in order of priority
|
||||
@@ -400,13 +398,6 @@ type Preamble = PreambleState;
|
||||
// 500 * 1024 / 8 * .8 * 0.5 / 2
|
||||
const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
|
||||
|
||||
function isEligibleForOutlining(
|
||||
request: Request,
|
||||
boundary: SuspenseBoundary,
|
||||
): boolean {
|
||||
return boundary.byteSize > request.progressiveChunkSize;
|
||||
}
|
||||
|
||||
function defaultErrorHandler(error: mixed) {
|
||||
if (
|
||||
typeof error === 'object' &&
|
||||
@@ -456,7 +447,6 @@ function RequestInstance(
|
||||
this.pendingRootTasks = 0;
|
||||
this.completedRootSegment = null;
|
||||
this.completedPreambleSegments = null;
|
||||
this.byteSize = 0;
|
||||
this.abortableTasks = abortSet;
|
||||
this.pingedTasks = pingedTasks;
|
||||
this.clientRenderedBoundaries = ([]: Array<SuspenseBoundary>);
|
||||
@@ -1245,7 +1235,6 @@ function renderSuspenseBoundary(
|
||||
boundarySegment.textEmbedded,
|
||||
);
|
||||
boundarySegment.status = COMPLETED;
|
||||
finishedSegment(request, parentBoundary, boundarySegment);
|
||||
} catch (thrownValue: mixed) {
|
||||
if (request.status === ABORTING) {
|
||||
boundarySegment.status = ABORTED;
|
||||
@@ -1312,24 +1301,20 @@ function renderSuspenseBoundary(
|
||||
contentRootSegment.textEmbedded,
|
||||
);
|
||||
contentRootSegment.status = COMPLETED;
|
||||
finishedSegment(request, newBoundary, contentRootSegment);
|
||||
queueCompletedSegment(newBoundary, contentRootSegment);
|
||||
if (newBoundary.pendingTasks === 0 && newBoundary.status === PENDING) {
|
||||
// This must have been the last segment we were waiting on. This boundary is now complete.
|
||||
newBoundary.status = COMPLETED;
|
||||
// Therefore we won't need the fallback. We early return so that we don't have to create
|
||||
// the fallback. However, if this boundary ended up big enough to be eligible for outlining
|
||||
// we can't do that because we might still need the fallback if we outline it.
|
||||
if (!isEligibleForOutlining(request, newBoundary)) {
|
||||
if (request.pendingRootTasks === 0 && task.blockedPreamble) {
|
||||
// The root is complete and this boundary may contribute part of the preamble.
|
||||
// We eagerly attempt to prepare the preamble here because we expect most requests
|
||||
// to have few boundaries which contribute preambles and it allow us to do this
|
||||
// preparation work during the work phase rather than the when flushing.
|
||||
preparePreamble(request);
|
||||
}
|
||||
return;
|
||||
// the fallback.
|
||||
newBoundary.status = COMPLETED;
|
||||
if (request.pendingRootTasks === 0 && task.blockedPreamble) {
|
||||
// The root is complete and this boundary may contribute part of the preamble.
|
||||
// We eagerly attempt to prepare the preamble here because we expect most requests
|
||||
// to have few boundaries which contribute preambles and it allow us to do this
|
||||
// preparation work during the work phase rather than the when flushing.
|
||||
preparePreamble(request);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (thrownValue: mixed) {
|
||||
newBoundary.status = CLIENT_RENDERED;
|
||||
@@ -2466,7 +2451,6 @@ function resumeNode(
|
||||
renderTask.blockedSegment = resumedSegment;
|
||||
renderNode(request, task, node, childIndex);
|
||||
resumedSegment.status = COMPLETED;
|
||||
finishedSegment(request, blockedBoundary, resumedSegment);
|
||||
if (blockedBoundary === null) {
|
||||
request.completedRootSegment = resumedSegment;
|
||||
} else {
|
||||
@@ -4288,27 +4272,6 @@ function queueCompletedSegment(
|
||||
}
|
||||
}
|
||||
|
||||
function finishedSegment(
|
||||
request: Request,
|
||||
boundary: Root | SuspenseBoundary,
|
||||
segment: Segment,
|
||||
) {
|
||||
if (byteLengthOfChunk !== null) {
|
||||
// Count the bytes of all the chunks of this segment.
|
||||
const chunks = segment.chunks;
|
||||
let segmentByteSize = 0;
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
segmentByteSize += byteLengthOfChunk(chunks[i]);
|
||||
}
|
||||
// Accumulate on the parent boundary to power heuristics.
|
||||
if (boundary === null) {
|
||||
request.byteSize += segmentByteSize;
|
||||
} else {
|
||||
boundary.byteSize += segmentByteSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function finishedTask(
|
||||
request: Request,
|
||||
boundary: Root | SuspenseBoundary,
|
||||
@@ -4355,13 +4318,9 @@ function finishedTask(
|
||||
// This needs to happen after we read the parentFlushed flags because aborting can finish
|
||||
// work which can trigger user code, which can start flushing, which can change those flags.
|
||||
// If the boundary was POSTPONED, we still need to finish the fallback first.
|
||||
// If the boundary is eligible to be outlined during flushing we can't cancel the fallback
|
||||
// since we might need it when it's being outlined.
|
||||
if (boundary.status === COMPLETED) {
|
||||
if (!isEligibleForOutlining(request, boundary)) {
|
||||
boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
|
||||
boundary.fallbackAbortableTasks.clear();
|
||||
}
|
||||
boundary.fallbackAbortableTasks.forEach(abortTaskSoft, request);
|
||||
boundary.fallbackAbortableTasks.clear();
|
||||
|
||||
if (
|
||||
request.pendingRootTasks === 0 &&
|
||||
@@ -4459,7 +4418,6 @@ function retryRenderTask(
|
||||
|
||||
task.abortSet.delete(task);
|
||||
segment.status = COMPLETED;
|
||||
finishedSegment(request, task.blockedBoundary, segment);
|
||||
finishedTask(request, task.blockedBoundary, segment);
|
||||
} catch (thrownValue: mixed) {
|
||||
resetHooksState();
|
||||
@@ -4971,7 +4929,7 @@ function flushSegment(
|
||||
flushSubtree(request, destination, segment, hoistableState);
|
||||
|
||||
return writeEndPendingSuspenseBoundary(destination, request.renderState);
|
||||
} else if (isEligibleForOutlining(request, boundary)) {
|
||||
} else if (boundary.byteSize > request.progressiveChunkSize) {
|
||||
// This boundary is large and will be emitted separately so that we can progressively show
|
||||
// other content. We add it to the queue during the flush because we have to ensure that
|
||||
// the parent flushes first so that there's something to inject it into.
|
||||
|
||||
@@ -60,9 +60,9 @@ export function typedArrayToBinaryChunk(
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
export const byteLengthOfChunk:
|
||||
| null
|
||||
| ((chunk: Chunk | PrecomputedChunk) => number) = null;
|
||||
export function byteLengthOfChunk(chunk: Chunk | PrecomputedChunk): number {
|
||||
throw new Error('Not implemented.');
|
||||
}
|
||||
|
||||
export function byteLengthOfBinaryChunk(chunk: BinaryChunk): number {
|
||||
throw new Error('Not implemented.');
|
||||
|
||||
Reference in New Issue
Block a user