diff --git a/fixtures/scheduler/index.html b/fixtures/scheduler/index.html index 5da9d66163010..4bc57fbd9a7cf 100644 --- a/fixtures/scheduler/index.html +++ b/fixtures/scheduler/index.html @@ -91,19 +91,8 @@

Tests:

If the counter advanced while you were away from this tab, it's correct.
  • -

    Can pause execution, dump scheduled callbacks, and continue where it left off

    - -
    Click the button above, press "continue" to finish the test after it pauses:
    - -
    Expected:
    -
    -
    -
    -------------------------------------------------
    -
    If the test didn't progress until you hit "continue" and
    -
    you see the same above and below afterwards it's correct. -
    -------------------------------------------------
    -
    Actual:
    -
    +

    Test Eight Removed

    +

    Test 8 was removed because it was testing a feature that was removed from the scheduler.

  • Can force a specific framerate

    @@ -156,9 +145,6 @@

    Tests:

    unstable_scheduleCallback: scheduleCallback, unstable_cancelCallback: cancelCallback, unstable_now: now, - unstable_getFirstCallbackNode: getFirstCallbackNode, - unstable_pauseExecution: pauseExecution, - unstable_continueExecution: continueExecution, unstable_forceFrameRate: forceFrameRate, unstable_shouldYield: shouldYield, unstable_NormalPriority: NormalPriority, @@ -587,50 +573,6 @@

    Tests:

    scheduleCallback(NormalPriority, incrementCounterAndScheduleNextCallback); } -function runTestEight() { - // Test 8 - // Pauses execution, dumps the queue, and continues execution - clearTestResult(8); - - function countNodesInStack(firstCallbackNode) { - var node = firstCallbackNode; - var count = 0; - if (node !== null) { - do { - count = count + 1; - node = node.next; - } while (node !== firstCallbackNode); - } - return count; - } - - scheduleCallback(NormalPriority, () => { - - // size should be 0 - updateTestResult(8, `Queue size: ${countNodesInStack(getFirstCallbackNode())}.`); - updateTestResult(8, 'Pausing... press continue to resume.'); - pauseExecution(); - - scheduleCallback(NormalPriority, function () { - updateTestResult(8, 'Finishing...'); - displayTestResult(8); - }) - scheduleCallback(NormalPriority, function () { - updateTestResult(8, 'Done!'); - displayTestResult(8); - checkTestResult(8); - }) - - // new size should be 2 now - updateTestResult(8, `Queue size: ${countNodesInStack(getFirstCallbackNode())}.`); - displayTestResult(8); - }); -} - -function continueTestEight() { - continueExecution(); -} - function runTestNine() { clearTestResult(9); // We have this to make sure that the thing that goes right after it can get a full frame diff --git a/packages/react-dom-bindings/src/client/validateDOMNesting.js b/packages/react-dom-bindings/src/client/validateDOMNesting.js index 49d8b5c158f62..d6fdc5e857ed3 100644 --- a/packages/react-dom-bindings/src/client/validateDOMNesting.js +++ b/packages/react-dom-bindings/src/client/validateDOMNesting.js @@ -297,6 +297,8 @@ function isTagValidWithParent(tag: string, parentTag: ?string): boolean { tag === 'hr' || tag === 'option' || tag === 'optgroup' || + tag === 'script' || + tag === 'template' || tag === '#text' ); case 'optgroup': diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index a71eb543cfe5d..7377f605a8811 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -32,7 +32,6 @@ import { enableSchedulingProfiler, enableUpdaterTracking, enableTransitionTracing, - useModernStrictMode, disableLegacyContext, alwaysThrottleRetries, enableInfiniteRenderLoopDetection, @@ -4205,7 +4204,7 @@ function commitDoubleInvokeEffectsInDEV( hasPassiveEffects: boolean, ) { if (__DEV__) { - if (useModernStrictMode && (disableLegacyMode || root.tag !== LegacyRoot)) { + if (disableLegacyMode || root.tag !== LegacyRoot) { let doubleInvokeEffects = true; if ( diff --git a/packages/react-reconciler/src/__tests__/ActivityStrictMode-test.js b/packages/react-reconciler/src/__tests__/ActivityStrictMode-test.js index 85365d3e708fc..12b319080de5c 100644 --- a/packages/react-reconciler/src/__tests__/ActivityStrictMode-test.js +++ b/packages/react-reconciler/src/__tests__/ActivityStrictMode-test.js @@ -77,7 +77,7 @@ describe('Activity StrictMode', () => { ]); }); - // @gate __DEV__ && enableActivity && useModernStrictMode + // @gate __DEV__ && enableActivity it('should not trigger strict effects when offscreen is hidden', async () => { await act(() => { ReactNoop.render( diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js index 0ce01a650c323..0c7e75c39a4a5 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js @@ -945,34 +945,25 @@ describe('StrictEffectsMode', () => { shouldSuspend = false; }); - if (gate(flags => flags.useModernStrictMode)) { - expect(log).toEqual([ - 'Child rendered', - 'Child rendered', - // !!! Committed, destroy and create effect. - // !!! The other effect is not destroyed and created - // !!! because the dep didn't change - 'Child dep destroy', - 'Child dep create', - - // Double invoke both effects - 'Child destroy', - 'Child dep destroy', - 'Child create', - 'Child dep create', - // Fires setState - '-----------------------after setState', - 'Child rendered', - 'Child rendered', - 'Child dep create', - ]); - } else { - expect(log).toEqual([ - 'Child rendered', - 'Child rendered', - 'Child dep destroy', - 'Child dep create', - ]); - } + expect(log).toEqual([ + 'Child rendered', + 'Child rendered', + // !!! Committed, destroy and create effect. + // !!! The other effect is not destroyed and created + // !!! because the dep didn't change + 'Child dep destroy', + 'Child dep create', + + // Double invoke both effects + 'Child destroy', + 'Child dep destroy', + 'Child create', + 'Child dep create', + // Fires setState + '-----------------------after setState', + 'Child rendered', + 'Child rendered', + 'Child dep create', + ]); }); }); diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js index c9f65a20a0c7b..5829cd0904266 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js @@ -461,7 +461,6 @@ describe('StrictEffectsMode defaults', () => { expect(log).toEqual([]); }); - //@gate useModernStrictMode it('disconnects refs during double invoking', async () => { const onRefMock = jest.fn(); function App({text}) { diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReplyEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReplyEdge-test.js index 0c6ec9599e1e2..f6157dff171d7 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReplyEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReplyEdge-test.js @@ -245,4 +245,31 @@ describe('ReactFlightDOMReplyEdge', () => { ), ); }); + + it('should abort when parsing an incomplete payload', async () => { + const infinitePromise = new Promise(() => {}); + const controller = new AbortController(); + const promiseForResult = ReactServerDOMClient.encodeReply( + {promise: infinitePromise}, + { + signal: controller.signal, + }, + ); + controller.abort(); + const body = await promiseForResult; + + const decoded = await ReactServerDOMServer.decodeReply( + body, + webpackServerMap, + ); + + let error = null; + try { + await decoded.promise; + } catch (x) { + error = x; + } + expect(error).not.toBe(null); + expect(error.message).toBe('Connection closed.'); + }); }); diff --git a/packages/react-server/src/ReactFlightReplyServer.js b/packages/react-server/src/ReactFlightReplyServer.js index 930998ea3d889..4db7571bb66a6 100644 --- a/packages/react-server/src/ReactFlightReplyServer.js +++ b/packages/react-server/src/ReactFlightReplyServer.js @@ -169,6 +169,8 @@ export type Response = { _prefix: string, _formData: FormData, _chunks: Map>, + _closed: boolean, + _closedReason: mixed, _temporaryReferences: void | TemporaryReferenceSet, }; @@ -255,6 +257,14 @@ function createResolvedModelChunk( return new Chunk(RESOLVED_MODEL, value, id, response); } +function createErroredChunk( + response: Response, + reason: mixed, +): ErroredChunk { + // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors + return new Chunk(ERRORED, null, reason, response); +} + function resolveModelChunk( chunk: SomeChunk, value: string, @@ -493,6 +503,8 @@ function initializeModelChunk(chunk: ResolvedModelChunk): 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 @@ -514,6 +526,10 @@ function getChunk(response: Response, id: number): SomeChunk { if (backingEntry != null) { // We assume that this is a string entry for now. chunk = createResolvedModelChunk(response, (backingEntry: any), id); + } else 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 = createErroredChunk(response, response._closedReason); } else { // We're still waiting on this entry to stream in. chunk = createPendingChunk(response); @@ -1082,6 +1098,8 @@ export function createResponse( _prefix: formFieldPrefix, _formData: backingFormData, _chunks: chunks, + _closed: false, + _closedReason: null, _temporaryReferences: temporaryReferences, }; return response; diff --git a/packages/react/src/__tests__/ReactStrictMode-test.internal.js b/packages/react/src/__tests__/ReactStrictMode-test.internal.js index ed9ee70279648..2867e06483792 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.internal.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.internal.js @@ -179,6 +179,40 @@ describe('ReactStrictMode', () => { 'B: useEffect mount', ]); }); + + it('should support nested strict mode on initial mount', async () => { + function Wrapper({children}) { + return children; + } + await act(() => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + root.render( + + + + , + + , + , + ); + }); + + expect(log).toEqual([ + 'A: render', + 'B: render', + 'B: render', + 'A: useLayoutEffect mount', + 'B: useLayoutEffect mount', + 'A: useEffect mount', + 'B: useEffect mount', + // TODO: this is currently broken + // 'B: useLayoutEffect unmount', + // 'B: useEffect unmount', + // 'B: useLayoutEffect mount', + // 'B: useEffect mount', + ]); + }); } }); }); diff --git a/packages/scheduler/src/SchedulerFeatureFlags.js b/packages/scheduler/src/SchedulerFeatureFlags.js index a5166f9813193..6828d0105ebb5 100644 --- a/packages/scheduler/src/SchedulerFeatureFlags.js +++ b/packages/scheduler/src/SchedulerFeatureFlags.js @@ -7,7 +7,6 @@ * @flow strict */ -export const enableSchedulerDebugging = false; export const enableProfiling = false; export const frameYieldMs = 5; diff --git a/packages/scheduler/src/forks/Scheduler.js b/packages/scheduler/src/forks/Scheduler.js index 3fe4d1720fc38..8b34f26bd0551 100644 --- a/packages/scheduler/src/forks/Scheduler.js +++ b/packages/scheduler/src/forks/Scheduler.js @@ -12,7 +12,6 @@ import type {PriorityLevel} from '../SchedulerPriorities'; import { - enableSchedulerDebugging, enableProfiling, frameYieldMs, userBlockingPriorityTimeout, @@ -83,9 +82,6 @@ var timerQueue: Array = []; // Incrementing id counter. Used to maintain insertion order. var taskIdCounter = 1; -// Pausing the scheduler is useful for debugging. -var isSchedulerPaused = false; - var currentTask = null; var currentPriorityLevel = NormalPriority; @@ -193,10 +189,7 @@ function workLoop(initialTime: number) { let currentTime = initialTime; advanceTimers(currentTime); currentTask = peek(taskQueue); - while ( - currentTask !== null && - !(enableSchedulerDebugging && isSchedulerPaused) - ) { + while (currentTask !== null) { if (!enableAlwaysYieldScheduler) { if (currentTask.expirationTime > currentTime && shouldYieldToHost()) { // This currentTask hasn't expired, and we've reached the deadline. @@ -422,22 +415,6 @@ function unstable_scheduleCallback( return newTask; } -function unstable_pauseExecution() { - isSchedulerPaused = true; -} - -function unstable_continueExecution() { - isSchedulerPaused = false; - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(); - } -} - -function unstable_getFirstCallbackNode(): Task | null { - return peek(taskQueue); -} - function unstable_cancelCallback(task: Task) { if (enableProfiling) { if (task.isQueued) { @@ -606,9 +583,6 @@ export { unstable_getCurrentPriorityLevel, shouldYieldToHost as unstable_shouldYield, requestPaint as unstable_requestPaint, - unstable_continueExecution, - unstable_pauseExecution, - unstable_getFirstCallbackNode, getCurrentTime as unstable_now, forceFrameRate as unstable_forceFrameRate, }; diff --git a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js index 1d6b955eb8888..2873dee099787 100644 --- a/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js +++ b/packages/scheduler/src/forks/SchedulerFeatureFlags.www.js @@ -12,7 +12,6 @@ const dynamicFeatureFlags = require('SchedulerFeatureFlags'); export const {enableRequestPaint} = dynamicFeatureFlags; -export const enableSchedulerDebugging = false; export const enableProfiling = __DEV__; export const frameYieldMs = 10; diff --git a/packages/scheduler/src/forks/SchedulerMock.js b/packages/scheduler/src/forks/SchedulerMock.js index 7f148c45be3e4..b638bf1eaf519 100644 --- a/packages/scheduler/src/forks/SchedulerMock.js +++ b/packages/scheduler/src/forks/SchedulerMock.js @@ -12,10 +12,7 @@ import type {PriorityLevel} from '../SchedulerPriorities'; -import { - enableSchedulerDebugging, - enableProfiling, -} from '../SchedulerFeatureFlags'; +import {enableProfiling} from '../SchedulerFeatureFlags'; import {push, pop, peek} from '../SchedulerMinHeap'; // TODO: Use symbols? @@ -72,9 +69,6 @@ var timerQueue: Array = []; // Incrementing id counter. Used to maintain insertion order. var taskIdCounter = 1; -// Pausing the scheduler is useful for debugging. -var isSchedulerPaused = false; - var currentTask = null; var currentPriorityLevel = NormalPriority; @@ -195,10 +189,7 @@ function workLoop(hasTimeRemaining: boolean, initialTime: number): boolean { let currentTime = initialTime; advanceTimers(currentTime); currentTask = peek(taskQueue); - while ( - currentTask !== null && - !(enableSchedulerDebugging && isSchedulerPaused) - ) { + while (currentTask !== null) { if ( currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost()) @@ -422,22 +413,6 @@ function unstable_scheduleCallback( return newTask; } -function unstable_pauseExecution() { - isSchedulerPaused = true; -} - -function unstable_continueExecution() { - isSchedulerPaused = false; - if (!isHostCallbackScheduled && !isPerformingWork) { - isHostCallbackScheduled = true; - requestHostCallback(flushWork); - } -} - -function unstable_getFirstCallbackNode(): Task | null { - return peek(taskQueue); -} - function unstable_cancelCallback(task: Task) { if (enableProfiling) { if (task.isQueued) { @@ -679,9 +654,6 @@ export { unstable_getCurrentPriorityLevel, shouldYieldToHost as unstable_shouldYield, requestPaint as unstable_requestPaint, - unstable_continueExecution, - unstable_pauseExecution, - unstable_getFirstCallbackNode, getCurrentTime as unstable_now, forceFrameRate as unstable_forceFrameRate, unstable_flushAllWithoutAsserting, diff --git a/packages/scheduler/src/forks/SchedulerNative.js b/packages/scheduler/src/forks/SchedulerNative.js index 3832cbc69753e..33f9ae3313534 100644 --- a/packages/scheduler/src/forks/SchedulerNative.js +++ b/packages/scheduler/src/forks/SchedulerNative.js @@ -97,9 +97,6 @@ export const unstable_now: () => number | DOMHighResTimeStamp = export const unstable_next: any = throwNotImplemented; export const unstable_runWithPriority: any = throwNotImplemented; export const unstable_wrapCallback: any = throwNotImplemented; -export const unstable_continueExecution: any = throwNotImplemented; -export const unstable_pauseExecution: any = throwNotImplemented; -export const unstable_getFirstCallbackNode: any = throwNotImplemented; export const unstable_forceFrameRate: any = throwNotImplemented; export const unstable_Profiling: any = null; diff --git a/packages/scheduler/src/forks/SchedulerPostTask.js b/packages/scheduler/src/forks/SchedulerPostTask.js index a029fce0cbfcc..7465c38b92f8a 100644 --- a/packages/scheduler/src/forks/SchedulerPostTask.js +++ b/packages/scheduler/src/forks/SchedulerPostTask.js @@ -234,13 +234,5 @@ export function unstable_wrapCallback(callback: () => T): () => T { export function unstable_forceFrameRate() {} -export function unstable_pauseExecution() {} - -export function unstable_continueExecution() {} - -export function unstable_getFirstCallbackNode(): null { - return null; -} - // Currently no profiling build export const unstable_Profiling = null; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 8540d6e14721a..7d45abe69f5a9 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -186,12 +186,6 @@ export const disableLegacyContext = true; */ export const disableLegacyContextForFunctionComponents = true; -// Not ready to break experimental yet. -// Modern behaviour aligns more with what components -// components will encounter in production, especially when used With . -// TODO: clean up legacy once tests pass WWW. -export const useModernStrictMode = true; - // Enable the moveBefore() alternative to insertBefore(). This preserves states of moves. export const enableMoveBefore = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 45807e9d876af..73ccd5fb8eda9 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -80,7 +80,6 @@ export const renameElementSymbol = false; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; -export const useModernStrictMode = true; export const enableHydrationLaneScheduling = true; export const enableYieldingBeforePassive = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index c29da18a42055..7699aa73f7fa7 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -70,7 +70,6 @@ export const renameElementSymbol = true; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; -export const useModernStrictMode = true; export const enableSiblingPrerendering = true; export const enableUseResourceEffectHook = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index df58c53eda9a4..c23c4ba131a72 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -52,7 +52,6 @@ export const enableLegacyHidden = false; export const enableTransitionTracing = false; -export const useModernStrictMode = true; export const enableDO_NOT_USE_disableStrictPassiveEffect = false; export const enableFizzExternalRuntime = true; export const enableDeferRootSchedulingToMicrotask = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index a4dc5cb76d109..8574f34c4e952 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -65,7 +65,6 @@ export const renameElementSymbol = false; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; -export const useModernStrictMode = true; export const enableFabricCompleteRootInCommitPhase = false; export const enableSiblingPrerendering = true; export const enableUseResourceEffectHook = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index e7c92602a0abf..97743f0d46ae9 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -54,7 +54,6 @@ export const enableLegacyHidden = false; export const enableTransitionTracing = false; -export const useModernStrictMode = true; export const enableDO_NOT_USE_disableStrictPassiveEffect = false; export const enableFizzExternalRuntime = false; export const enableDeferRootSchedulingToMicrotask = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index da62754a13359..c027e2bdc121c 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -106,7 +106,6 @@ export const disableClientCache = true; export const enableServerComponentLogs = true; export const enableReactTestRendererWarning = false; -export const useModernStrictMode = true; export const disableLegacyMode = true; diff --git a/scripts/jest/setupTests.www.js b/scripts/jest/setupTests.www.js index efee213861ca6..b0b653bb78ff9 100644 --- a/scripts/jest/setupTests.www.js +++ b/scripts/jest/setupTests.www.js @@ -34,9 +34,9 @@ jest.mock('scheduler/src/SchedulerFeatureFlags', () => { schedulerSrcPath + '/src/forks/SchedulerFeatureFlags.www' ); - // These flags are not a dynamic on www, but we still want to run - // tests in both versions. - actual.enableSchedulerDebugging = __VARIANT__; + // Add flags here that are not a dynamic on www, + // but we still want to run tests in both versions. + // return actual; });