Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from facebook:main #33

Merged
merged 5 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions ReactVersions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,47 @@
//
// The @latest channel uses the version as-is, e.g.:
//
// 19.0.0
// 19.1.0
//
// The @canary channel appends additional information, with the scheme
// <version>-<label>-<commit_sha>, e.g.:
//
// 19.0.0-canary-a1c2d3e4
// 19.1.0-canary-a1c2d3e4
//
// The @experimental channel doesn't include a version, only a date and a sha, e.g.:
//
// 0.0.0-experimental-241c4467e-20200129

const ReactVersion = '19.0.0';
const ReactVersion = '19.1.0';

// The label used by the @canary channel. Represents the upcoming release's
// stability. Most of the time, this will be "canary", but we may temporarily
// choose to change it to "alpha", "beta", "rc", etc.
//
// It only affects the label used in the version string. To customize the
// npm dist tags used during publish, refer to .github/workflows/runtime_prereleases_*.yml.
const canaryChannelLabel = 'rc';
const canaryChannelLabel = 'canary';

// If the canaryChannelLabel is "rc", the build pipeline will use this to build
// an RC version of the packages.
const rcNumber = 1;
const rcNumber = 0;

const stablePackages = {
'eslint-plugin-react-hooks': '5.1.0',
'jest-react': '0.16.0',
'eslint-plugin-react-hooks': '5.2.0',
'jest-react': '0.17.0',
react: ReactVersion,
'react-art': ReactVersion,
'react-dom': ReactVersion,
'react-server-dom-webpack': ReactVersion,
'react-server-dom-turbopack': ReactVersion,
'react-server-dom-parcel': ReactVersion,
'react-is': ReactVersion,
'react-reconciler': '0.31.0',
'react-refresh': '0.16.0',
'react-reconciler': '0.32.0',
'react-refresh': '0.17.0',
'react-test-renderer': ReactVersion,
'use-subscription': '1.10.0',
'use-sync-external-store': '1.4.0',
scheduler: '0.25.0',
'use-subscription': '1.11.0',
'use-sync-external-store': '1.5.0',
scheduler: '0.26.0',
};

// These packages do not exist in the @canary or @latest channel, only
Expand Down
18 changes: 17 additions & 1 deletion fixtures/flight/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,26 @@ import {like, greet, increment} from './actions.js';
import {getServerState} from './ServerState.js';

const promisedText = new Promise(resolve =>
setTimeout(() => resolve('deferred text'), 100)
setTimeout(() => resolve('deferred text'), 50)
);

function Foo({children}) {
return <div>{children}</div>;
}

function Bar({children}) {
return <div>{children}</div>;
}

async function ServerComponent() {
await new Promise(resolve => setTimeout(() => resolve('deferred text'), 50));
}

export default async function App({prerender}) {
const res = await fetch('http://localhost:3001/todos');
const todos = await res.json();

const dedupedChild = <ServerComponent />;
return (
<html lang="en">
<head>
Expand Down Expand Up @@ -66,6 +80,8 @@ export default async function App({prerender}) {
</div>
<Client />
<Note />
<Foo>{dedupedChild}</Foo>
<Bar>{dedupedChild}</Bar>
</Container>
</body>
</html>
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-react-hooks/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "eslint-plugin-react-hooks",
"description": "ESLint rules for React Hooks",
"version": "5.0.0",
"version": "5.2.0",
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jest-react",
"version": "0.14.0",
"version": "0.17.0",
"description": "Jest matchers and utilities for testing React components.",
"main": "index.js",
"repository": {
Expand Down
6 changes: 3 additions & 3 deletions packages/react-art/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-art",
"description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
"version": "19.0.0",
"version": "19.1.0",
"main": "index.js",
"repository": {
"type": "git",
Expand All @@ -24,7 +24,7 @@
"dependencies": {
"art": "^0.10.1",
"create-react-class": "^15.6.2",
"scheduler": "^0.23.0"
"scheduler": "^0.25.0"
},
"peerDependencies": {
"react": "^19.0.0"
Expand All @@ -38,4 +38,4 @@
"Rectangle.js",
"Wedge.js"
]
}
}
124 changes: 117 additions & 7 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import {createBoundServerReference} from './ReactFlightReplyClient';

import {readTemporaryReference} from './ReactFlightTemporaryReferences';

import {logComponentRender} from './ReactFlightPerformanceTrack';

import {
REACT_LAZY_TYPE,
REACT_ELEMENT_TYPE,
Expand Down Expand Up @@ -124,6 +126,10 @@ export type JSONValue =
| {+[key: string]: JSONValue}
| $ReadOnlyArray<JSONValue>;

type ProfilingResult = {
endTime: number,
};

const ROW_ID = 0;
const ROW_TAG = 1;
const ROW_LENGTH = 2;
Expand All @@ -144,39 +150,44 @@ type PendingChunk<T> = {
value: null | Array<(T) => mixed>,
reason: null | Array<(mixed) => mixed>,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type BlockedChunk<T> = {
status: 'blocked',
value: null | Array<(T) => mixed>,
reason: null | Array<(mixed) => mixed>,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type ResolvedModelChunk<T> = {
status: 'resolved_model',
value: UninitializedModel,
reason: null,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type ResolvedModuleChunk<T> = {
status: 'resolved_module',
value: ClientReference<T>,
reason: null,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type InitializedChunk<T> = {
status: 'fulfilled',
value: T,
reason: null | FlightStreamController,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type InitializedStreamChunk<
Expand All @@ -186,15 +197,17 @@ type InitializedStreamChunk<
value: T,
reason: FlightStreamController,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (ReadableStream) => mixed, reject?: (mixed) => mixed): void,
};
type ErroredChunk<T> = {
status: 'rejected',
value: null,
reason: mixed,
_response: Response,
_debugInfo?: null | ReactDebugInfo,
_children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only
_debugInfo?: null | ReactDebugInfo, // DEV-only
then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,
};
type SomeChunk<T> =
Expand All @@ -216,6 +229,9 @@ function ReactPromise(
this.value = value;
this.reason = reason;
this._response = response;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
this._children = [];
}
if (__DEV__) {
this._debugInfo = null;
}
Expand Down Expand Up @@ -548,9 +564,11 @@ type InitializationHandler = {
errored: boolean,
};
let initializingHandler: null | InitializationHandler = null;
let initializingChunk: null | BlockedChunk<any> = null;

function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
const prevHandler = initializingHandler;
const prevChunk = initializingChunk;
initializingHandler = null;

const resolvedModel = chunk.value;
Expand All @@ -563,6 +581,10 @@ function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
cyclicChunk.value = null;
cyclicChunk.reason = null;

if (enableProfilerTimer && enableComponentPerformanceTrack) {
initializingChunk = cyclicChunk;
}

try {
const value: T = parseModel(chunk._response, resolvedModel);
// Invoke any listeners added while resolving this model. I.e. cyclic
Expand Down Expand Up @@ -595,6 +617,9 @@ function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
erroredChunk.reason = error;
} finally {
initializingHandler = prevHandler;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
initializingChunk = prevChunk;
}
}
}

Expand Down Expand Up @@ -622,6 +647,9 @@ export function reportGlobalError(response: Response, error: Error): void {
triggerErrorOnChunk(chunk, error);
}
});
if (enableProfilerTimer && enableComponentPerformanceTrack) {
flushComponentPerformance(getChunk(response, 0));
}
}

function nullRefGetter() {
Expand Down Expand Up @@ -1210,6 +1238,11 @@ function getOutlinedModel<T>(
const path = reference.split(':');
const id = parseInt(path[0], 16);
const chunk = getChunk(response, id);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (initializingChunk !== null && isArray(initializingChunk._children)) {
initializingChunk._children.push(chunk);
}
}
switch (chunk.status) {
case RESOLVED_MODEL:
initializeModelChunk(chunk);
Expand Down Expand Up @@ -1359,6 +1392,14 @@ function parseModelString(
// Lazy node
const id = parseInt(value.slice(2), 16);
const chunk = getChunk(response, id);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (
initializingChunk !== null &&
isArray(initializingChunk._children)
) {
initializingChunk._children.push(chunk);
}
}
// We create a React.lazy wrapper around any lazy values.
// When passed into React, we'll know how to suspend on this.
return createLazyChunkWrapper(chunk);
Expand All @@ -1371,6 +1412,14 @@ function parseModelString(
}
const id = parseInt(value.slice(2), 16);
const chunk = getChunk(response, id);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (
initializingChunk !== null &&
isArray(initializingChunk._children)
) {
initializingChunk._children.push(chunk);
}
}
return chunk;
}
case 'S': {
Expand Down Expand Up @@ -2704,6 +2753,67 @@ function resolveTypedArray(
resolveBuffer(response, id, view);
}

function flushComponentPerformance(root: SomeChunk<any>): number {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return 0;
}
// Write performance.measure() entries for Server Components in tree order.
// This must be done at the end to collect the end time from the whole tree.
if (!isArray(root._children)) {
// We have already written this chunk. If this was a cycle, then this will
// be -Infinity and it won't contribute to the parent end time.
// If this was already emitted by another sibling then we reused the same
// chunk in two places. We should extend the current end time as if it was
// rendered as part of this tree.
const previousResult: ProfilingResult = root._children;
return previousResult.endTime;
}
const children = root._children;
if (root.status === RESOLVED_MODEL) {
// If the model is not initialized by now, do that now so we can find its
// children. This part is a little sketchy since it significantly changes
// the performance characteristics of the app by profiling.
initializeModelChunk(root);
}
const result: ProfilingResult = {endTime: -Infinity};
root._children = result;
let childrenEndTime = -Infinity;
for (let i = 0; i < children.length; i++) {
const childEndTime = flushComponentPerformance(children[i]);
if (childEndTime > childrenEndTime) {
childrenEndTime = childEndTime;
}
}
const debugInfo = root._debugInfo;
if (debugInfo) {
let endTime = 0;
for (let i = debugInfo.length - 1; i >= 0; i--) {
const info = debugInfo[i];
if (typeof info.time === 'number') {
endTime = info.time;
if (endTime > childrenEndTime) {
childrenEndTime = endTime;
}
}
if (typeof info.name === 'string' && i > 0) {
// $FlowFixMe: Refined.
const componentInfo: ReactComponentInfo = info;
const startTimeInfo = debugInfo[i - 1];
if (typeof startTimeInfo.time === 'number') {
const startTime = startTimeInfo.time;
logComponentRender(
componentInfo,
startTime,
endTime,
childrenEndTime,
);
}
}
}
}
return (result.endTime = childrenEndTime);
}

function processFullBinaryRow(
response: Response,
id: number,
Expand Down
Loading
Loading