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 #48

Merged
merged 5 commits into from
Dec 19, 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
2 changes: 1 addition & 1 deletion .github/workflows/compiler_playground.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- .github/workflows/compiler_playground.yml

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/compiler_rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
- compiler/*.toml

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/compiler_typescript.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- .github/workflows/compiler_typescript.yml

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/runtime_build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- compiler/**

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/shared_lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

env:
Expand Down
16 changes: 14 additions & 2 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ export type Response = {
_rowTag: number, // 0 indicates that we're currently parsing the row ID
_rowLength: number, // remaining bytes in the row. 0 indicates that we're looking for a newline.
_buffer: Array<Uint8Array>, // chunks received so far as part of this row
_closed: boolean,
_closedReason: mixed,
_tempRefs: void | TemporaryReferenceSet, // the set temporary references can be resolved from
_timeOrigin: number, // Profiling-only
_debugRootOwner?: null | ReactComponentInfo, // DEV-only
Expand Down Expand Up @@ -358,7 +360,7 @@ function createBlockedChunk<T>(response: Response): BlockedChunk<T> {

function createErrorChunk<T>(
response: Response,
error: Error | Postpone,
error: mixed,
): ErroredChunk<T> {
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
return new ReactPromise(ERRORED, null, error, response);
Expand Down Expand Up @@ -639,6 +641,8 @@ function initializeModuleChunk<T>(chunk: ResolvedModuleChunk<T>): void {
// Report that any missing chunks in the model is now going to throw this
// error upon read. Also notify any pending promises.
export function reportGlobalError(response: Response, error: Error): void {
response._closed = true;
response._closedReason = error;
response._chunks.forEach(chunk => {
// If this chunk was already resolved or errored, it won't
// trigger an error but if it wasn't then we need to
Expand Down Expand Up @@ -913,7 +917,13 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
const chunks = response._chunks;
let chunk = chunks.get(id);
if (!chunk) {
chunk = createPendingChunk(response);
if (response._closed) {
// We have already errored the response and we're not going to get
// anything more streaming in so this will immediately error.
chunk = createErrorChunk(response, response._closedReason);
} else {
chunk = createPendingChunk(response);
}
chunks.set(id, chunk);
}
return chunk;
Expand Down Expand Up @@ -1640,6 +1650,8 @@ function ResponseInstance(
this._rowTag = 0;
this._rowLength = 0;
this._buffer = [];
this._closed = false;
this._closedReason = null;
this._tempRefs = temporaryReferences;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
this._timeOrigin = 0;
Expand Down
3 changes: 1 addition & 2 deletions packages/react-noop-renderer/src/ReactNoopFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Source = Array<Uint8Array>;

const decoderOptions = {stream: true};

const {createResponse, processBinaryChunk, getRoot, close} = ReactFlightClient({
const {createResponse, processBinaryChunk, getRoot} = ReactFlightClient({
createStringDecoder() {
return new TextDecoder();
},
Expand Down Expand Up @@ -74,7 +74,6 @@ function read<T>(source: Source, options: ReadOptions): Thenable<T> {
for (let i = 0; i < source.length; i++) {
processBinaryChunk(response, source[i], 0);
}
close(response);
return getRoot(response);
}

Expand Down
1 change: 1 addition & 0 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,7 @@ const SUSPENDED_MARKER: SuspenseState = {
dehydrated: null,
treeContext: null,
retryLane: NoLane,
hydrationErrors: null,
};

function mountSuspenseOffscreenState(renderLanes: Lanes): OffscreenState {
Expand Down
81 changes: 81 additions & 0 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import {
FormReset,
Cloned,
PerformedWork,
ForceClientRender,
} from './ReactFiberFlags';
import {
commitStartTime,
Expand All @@ -113,6 +114,7 @@ import {
import {
logComponentRender,
logComponentEffect,
logSuspenseBoundaryClientRendered,
} from './ReactFiberPerformanceTrack';
import {ConcurrentMode, NoMode, ProfileMode} from './ReactTypeOfMode';
import {deferHiddenCallbacks} from './ReactFiberClassUpdateQueue';
Expand Down Expand Up @@ -2689,6 +2691,8 @@ function recursivelyTraversePassiveMountEffects(
}
}

let inHydratedSubtree = false;

function commitPassiveMountOnFiber(
finishedRoot: FiberRoot,
finishedWork: Fiber,
Expand All @@ -2713,6 +2717,7 @@ function commitPassiveMountOnFiber(
finishedWork,
((finishedWork.actualStartTime: any): number),
endTime,
inHydratedSubtree,
);
}

Expand Down Expand Up @@ -2741,13 +2746,29 @@ function commitPassiveMountOnFiber(
}
case HostRoot: {
const prevEffectDuration = pushNestedEffectDurations();

const wasInHydratedSubtree = inHydratedSubtree;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
// Detect if this was a hydration commit by look at if the previous state was
// dehydrated and this wasn't a forced client render.
inHydratedSubtree =
finishedWork.alternate !== null &&
(finishedWork.alternate.memoizedState: RootState).isDehydrated &&
(finishedWork.flags & ForceClientRender) === NoFlags;
}

recursivelyTraversePassiveMountEffects(
finishedRoot,
finishedWork,
committedLanes,
committedTransitions,
endTime,
);

if (enableProfilerTimer && enableComponentPerformanceTrack) {
inHydratedSubtree = wasInHydratedSubtree;
}

if (flags & Passive) {
let previousCache: Cache | null = null;
if (finishedWork.alternate !== null) {
Expand Down Expand Up @@ -2841,6 +2862,64 @@ function commitPassiveMountOnFiber(
}
break;
}
case SuspenseComponent: {
const wasInHydratedSubtree = inHydratedSubtree;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
const prevState: SuspenseState | null =
finishedWork.alternate !== null
? finishedWork.alternate.memoizedState
: null;
const nextState: SuspenseState | null = finishedWork.memoizedState;
if (
prevState !== null &&
prevState.dehydrated !== null &&
(nextState === null || nextState.dehydrated === null)
) {
// This was dehydrated but is no longer dehydrated. We may have now either hydrated it
// or client rendered it.
const deletions = finishedWork.deletions;
if (
deletions !== null &&
deletions.length > 0 &&
deletions[0].tag === DehydratedFragment
) {
// This was an abandoned hydration that deleted the dehydrated fragment. That means we
// are not hydrating this Suspense boundary.
inHydratedSubtree = false;
const hydrationErrors = prevState.hydrationErrors;
// If there were no hydration errors, that suggests that this was an intentional client
// rendered boundary. Such as postpone.
if (hydrationErrors !== null) {
const startTime: number = (finishedWork.actualStartTime: any);
logSuspenseBoundaryClientRendered(
finishedWork,
startTime,
endTime,
hydrationErrors,
);
}
} else {
// If any children committed they were hydrated.
inHydratedSubtree = true;
}
} else {
inHydratedSubtree = false;
}
}

recursivelyTraversePassiveMountEffects(
finishedRoot,
finishedWork,
committedLanes,
committedTransitions,
endTime,
);

if (enableProfilerTimer && enableComponentPerformanceTrack) {
inHydratedSubtree = wasInHydratedSubtree;
}
break;
}
case LegacyHiddenComponent: {
if (enableLegacyHidden) {
recursivelyTraversePassiveMountEffects(
Expand Down Expand Up @@ -3074,6 +3153,7 @@ export function reconnectPassiveEffects(
finishedWork,
((finishedWork.actualStartTime: any): number),
endTime,
inHydratedSubtree,
);
}

Expand Down Expand Up @@ -3317,6 +3397,7 @@ function commitAtomicPassiveEffects(
finishedWork,
((finishedWork.actualStartTime: any): number),
endTime,
inHydratedSubtree,
);
}

Expand Down
10 changes: 7 additions & 3 deletions packages/react-reconciler/src/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -926,9 +926,13 @@ function completeDehydratedSuspenseBoundary(
// Successfully completed this tree. If this was a forced client render,
// there may have been recoverable errors during first hydration
// attempt. If so, add them to a queue so we can log them in the
// commit phase.
upgradeHydrationErrorsToRecoverable();

// commit phase. We also add them to prev state so we can get to them
// from the Suspense Boundary.
const hydrationErrors = upgradeHydrationErrorsToRecoverable();
if (current !== null && current.memoizedState !== null) {
const prevState: SuspenseState = current.memoizedState;
prevState.hydrationErrors = hydrationErrors;
}
// Fall through to normal Suspense path
return true;
}
Expand Down
11 changes: 8 additions & 3 deletions packages/react-reconciler/src/ReactFiberHydrationContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ function tryHydrateSuspense(fiber: Fiber, nextInstance: any) {
dehydrated: suspenseInstance,
treeContext: getSuspendedTreeContext(),
retryLane: OffscreenLane,
hydrationErrors: null,
};
fiber.memoizedState = suspenseState;
// Store the dehydrated fragment as a child fiber.
Expand Down Expand Up @@ -701,14 +702,18 @@ function resetHydrationState(): void {
didSuspendOrErrorDEV = false;
}

export function upgradeHydrationErrorsToRecoverable(): void {
if (hydrationErrors !== null) {
export function upgradeHydrationErrorsToRecoverable(): Array<
CapturedValue<mixed>,
> | null {
const queuedErrors = hydrationErrors;
if (queuedErrors !== null) {
// Successfully completed a forced client render. The errors that occurred
// during the hydration attempt are now recovered. We will log them in
// commit phase, once the entire tree has finished.
queueRecoverableErrors(hydrationErrors);
queueRecoverableErrors(queuedErrors);
hydrationErrors = null;
}
return queuedErrors;
}

function getIsHydrating(): boolean {
Expand Down
Loading
Loading