Skip to content

Commit

Permalink
Merge branch 'main' into ReactFreshRuntime-change
Browse files Browse the repository at this point in the history
  • Loading branch information
WellHiIGuess committed Apr 5, 2024
2 parents c386e27 + bfd8da8 commit 925930d
Show file tree
Hide file tree
Showing 36 changed files with 620 additions and 428 deletions.
34 changes: 27 additions & 7 deletions packages/react-client/src/ReactFlightClient.js
Expand Up @@ -484,6 +484,7 @@ function createElement(
type: mixed,
key: mixed,
props: mixed,
owner: null | ReactComponentInfo, // DEV-only
): React$Element<any> {
let element: any;
if (__DEV__ && enableRefAsProp) {
Expand All @@ -493,7 +494,7 @@ function createElement(
type,
key,
props,
_owner: null,
_owner: owner,
}: any);
Object.defineProperty(element, 'ref', {
enumerable: false,
Expand All @@ -520,7 +521,7 @@ function createElement(
props,

// Record the component responsible for creating this element.
_owner: null,
_owner: owner,
}: any);
}

Expand Down Expand Up @@ -736,6 +737,15 @@ function parseModelString(
const data = getOutlinedModel(response, id);
return new Set(data);
}
case 'B': {
// Blob
if (enableBinaryFlight) {
const id = parseInt(value.slice(2), 16);
const data = getOutlinedModel(response, id);
return new Blob(data.slice(1), {type: data[0]});
}
return undefined;
}
case 'I': {
// $Infinity
return Infinity;
Expand Down Expand Up @@ -854,7 +864,12 @@ function parseModelTuple(
if (tuple[0] === REACT_ELEMENT_TYPE) {
// TODO: Consider having React just directly accept these arrays as elements.
// Or even change the ReactElement type to be an array.
return createElement(tuple[1], tuple[2], tuple[3]);
return createElement(
tuple[1],
tuple[2],
tuple[3],
__DEV__ ? (tuple: any)[4] : null,
);
}
return value;
}
Expand Down Expand Up @@ -1132,12 +1147,14 @@ function resolveConsoleEntry(
);
}

const payload: [string, string, string, mixed] = parseModel(response, value);
const payload: [string, string, null | ReactComponentInfo, string, mixed] =
parseModel(response, value);
const methodName = payload[0];
// TODO: Restore the fake stack before logging.
// const stackTrace = payload[1];
const env = payload[2];
const args = payload.slice(3);
// const owner = payload[2];
const env = payload[3];
const args = payload.slice(4);
printToConsole(methodName, args, env);
}

Expand Down Expand Up @@ -1286,7 +1303,10 @@ function processFullRow(
}
case 68 /* "D" */: {
if (__DEV__) {
const debugInfo = JSON.parse(row);
const debugInfo: ReactComponentInfo | ReactAsyncInfo = parseModel(
response,
row,
);
resolveDebugInfo(response, id, debugInfo);
return;
}
Expand Down
58 changes: 53 additions & 5 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Expand Up @@ -214,7 +214,7 @@ describe('ReactFlight', () => {
const rootModel = await ReactNoopFlightClient.read(transport);
const greeting = rootModel.greeting;
expect(greeting._debugInfo).toEqual(
__DEV__ ? [{name: 'Greeting', env: 'Server'}] : undefined,
__DEV__ ? [{name: 'Greeting', env: 'Server', owner: null}] : undefined,
);
ReactNoop.render(greeting);
});
Expand All @@ -241,7 +241,7 @@ describe('ReactFlight', () => {
await act(async () => {
const promise = ReactNoopFlightClient.read(transport);
expect(promise._debugInfo).toEqual(
__DEV__ ? [{name: 'Greeting', env: 'Server'}] : undefined,
__DEV__ ? [{name: 'Greeting', env: 'Server', owner: null}] : undefined,
);
ReactNoop.render(await promise);
});
Expand Down Expand Up @@ -2072,19 +2072,21 @@ describe('ReactFlight', () => {
await act(async () => {
const promise = ReactNoopFlightClient.read(transport);
expect(promise._debugInfo).toEqual(
__DEV__ ? [{name: 'ServerComponent', env: 'Server'}] : undefined,
__DEV__
? [{name: 'ServerComponent', env: 'Server', owner: null}]
: undefined,
);
const result = await promise;
const thirdPartyChildren = await result.props.children[1];
// We expect the debug info to be transferred from the inner stream to the outer.
expect(thirdPartyChildren[0]._debugInfo).toEqual(
__DEV__
? [{name: 'ThirdPartyComponent', env: 'third-party'}]
? [{name: 'ThirdPartyComponent', env: 'third-party', owner: null}]
: undefined,
);
expect(thirdPartyChildren[1]._debugInfo).toEqual(
__DEV__
? [{name: 'ThirdPartyLazyComponent', env: 'third-party'}]
? [{name: 'ThirdPartyLazyComponent', env: 'third-party', owner: null}]
: undefined,
);
ReactNoop.render(result);
Expand Down Expand Up @@ -2145,4 +2147,50 @@ describe('ReactFlight', () => {
expect(loggedFn).not.toBe(foo);
expect(loggedFn.toString()).toBe(foo.toString());
});

it('uses the server component debug info as the element owner in DEV', async () => {
function Container({children}) {
return children;
}

function Greeting({firstName}) {
// We can't use JSX here because it'll use the Client React.
return ReactServer.createElement(
Container,
null,
ReactServer.createElement('span', null, 'Hello, ', firstName),
);
}

const model = {
greeting: ReactServer.createElement(Greeting, {firstName: 'Seb'}),
};

const transport = ReactNoopFlightServer.render(model);

await act(async () => {
const rootModel = await ReactNoopFlightClient.read(transport);
const greeting = rootModel.greeting;
// We've rendered down to the span.
expect(greeting.type).toBe('span');
if (__DEV__) {
const greetInfo = {name: 'Greeting', env: 'Server', owner: null};
expect(greeting._debugInfo).toEqual([
greetInfo,
{name: 'Container', env: 'Server', owner: greetInfo},
]);
// The owner that created the span was the outer server component.
// We expect the debug info to be referentially equal to the owner.
expect(greeting._owner).toBe(greeting._debugInfo[0]);
} else {
expect(greeting._debugInfo).toBe(undefined);
expect(greeting._owner).toBe(
gate(flags => flags.disableStringRefs) ? undefined : null,
);
}
ReactNoop.render(greeting);
});

expect(ReactNoop).toMatchRenderedOutput(<span>Hello, Seb</span>);
});
});
Expand Up @@ -101,6 +101,7 @@ describe('component stack', () => {
{
name: 'ServerComponent',
env: 'Server',
owner: null,
},
];
const Parent = () => ChildPromise;
Expand Down
Expand Up @@ -33,10 +33,7 @@ import {
import {disableLogs, reenableLogs} from './DevToolsConsolePatching';

let prefix;
export function describeBuiltInComponentFrame(
name: string,
ownerFn: void | null | Function,
): string {
export function describeBuiltInComponentFrame(name: string): string {
if (prefix === undefined) {
// Extract the VM specific prefix used by each line.
try {
Expand All @@ -51,10 +48,7 @@ export function describeBuiltInComponentFrame(
}

export function describeDebugInfoFrame(name: string, env: ?string): string {
return describeBuiltInComponentFrame(
name + (env ? ' (' + env + ')' : ''),
null,
);
return describeBuiltInComponentFrame(name + (env ? ' (' + env + ')' : ''));
}

let reentry = false;
Expand Down Expand Up @@ -292,15 +286,13 @@ export function describeNativeComponentFrame(

export function describeClassComponentFrame(
ctor: Function,
ownerFn: void | null | Function,
currentDispatcherRef: CurrentDispatcherRef,
): string {
return describeNativeComponentFrame(ctor, true, currentDispatcherRef);
}

export function describeFunctionComponentFrame(
fn: Function,
ownerFn: void | null | Function,
currentDispatcherRef: CurrentDispatcherRef,
): string {
return describeNativeComponentFrame(fn, false, currentDispatcherRef);
Expand All @@ -313,7 +305,6 @@ function shouldConstruct(Component: Function) {

export function describeUnknownElementTypeFrameInDEV(
type: any,
ownerFn: void | null | Function,
currentDispatcherRef: CurrentDispatcherRef,
): string {
if (!__DEV__) {
Expand All @@ -330,31 +321,29 @@ export function describeUnknownElementTypeFrameInDEV(
);
}
if (typeof type === 'string') {
return describeBuiltInComponentFrame(type, ownerFn);
return describeBuiltInComponentFrame(type);
}
switch (type) {
case SUSPENSE_NUMBER:
case SUSPENSE_SYMBOL_STRING:
return describeBuiltInComponentFrame('Suspense', ownerFn);
return describeBuiltInComponentFrame('Suspense');
case SUSPENSE_LIST_NUMBER:
case SUSPENSE_LIST_SYMBOL_STRING:
return describeBuiltInComponentFrame('SuspenseList', ownerFn);
return describeBuiltInComponentFrame('SuspenseList');
}
if (typeof type === 'object') {
switch (type.$$typeof) {
case FORWARD_REF_NUMBER:
case FORWARD_REF_SYMBOL_STRING:
return describeFunctionComponentFrame(
type.render,
ownerFn,
currentDispatcherRef,
);
case MEMO_NUMBER:
case MEMO_SYMBOL_STRING:
// Memo may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
type.type,
ownerFn,
currentDispatcherRef,
);
case LAZY_NUMBER:
Expand All @@ -366,7 +355,6 @@ export function describeUnknownElementTypeFrameInDEV(
// Lazy may contain any component type so we recursively resolve it.
return describeUnknownElementTypeFrameInDEV(
init(payload),
ownerFn,
currentDispatcherRef,
);
} catch (x) {}
Expand Down
Expand Up @@ -39,38 +39,30 @@ export function describeFiber(
ClassComponent,
} = workTagMap;

const owner: null | Function = __DEV__
? workInProgress._debugOwner
? workInProgress._debugOwner.type
: null
: null;
switch (workInProgress.tag) {
case HostComponent:
return describeBuiltInComponentFrame(workInProgress.type, owner);
return describeBuiltInComponentFrame(workInProgress.type);
case LazyComponent:
return describeBuiltInComponentFrame('Lazy', owner);
return describeBuiltInComponentFrame('Lazy');
case SuspenseComponent:
return describeBuiltInComponentFrame('Suspense', owner);
return describeBuiltInComponentFrame('Suspense');
case SuspenseListComponent:
return describeBuiltInComponentFrame('SuspenseList', owner);
return describeBuiltInComponentFrame('SuspenseList');
case FunctionComponent:
case IndeterminateComponent:
case SimpleMemoComponent:
return describeFunctionComponentFrame(
workInProgress.type,
owner,
currentDispatcherRef,
);
case ForwardRef:
return describeFunctionComponentFrame(
workInProgress.type.render,
owner,
currentDispatcherRef,
);
case ClassComponent:
return describeClassComponentFrame(
workInProgress.type,
owner,
currentDispatcherRef,
);
default:
Expand Down

0 comments on commit 925930d

Please sign in to comment.