diff --git a/packages/react-devtools-inline/src/backend.js b/packages/react-devtools-inline/src/backend.js index 849e103f218..2dd03417121 100644 --- a/packages/react-devtools-inline/src/backend.js +++ b/packages/react-devtools-inline/src/backend.js @@ -6,7 +6,10 @@ import {initBackend} from 'react-devtools-shared/src/backend'; import {installHook} from 'react-devtools-shared/src/hook'; import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; -import type {BackendBridge} from 'react-devtools-shared/src/bridge'; +import type { + BackendBridge, + SavedPreferencesParams, +} from 'react-devtools-shared/src/bridge'; import type {Wall} from 'react-devtools-shared/src/frontend/types'; import { getIfReloadedAndProfiling, @@ -16,31 +19,14 @@ import { } from 'react-devtools-shared/src/utils'; function startActivation(contentWindow: any, bridge: BackendBridge) { - const onSavedPreferences = (data: $FlowFixMe) => { + const onSavedPreferences = (data: SavedPreferencesParams) => { // This is the only message we're listening for, // so it's safe to cleanup after we've received it. bridge.removeListener('savedPreferences', onSavedPreferences); - const { - appendComponentStack, - breakOnConsoleErrors, - componentFilters, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - disableSecondConsoleLogDimmingInStrictMode, - } = data; - - contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = - appendComponentStack; - contentWindow.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = - breakOnConsoleErrors; + const {componentFilters} = data; + contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters; - contentWindow.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = - showInlineWarningsAndErrors; - contentWindow.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = - hideConsoleLogsInStrictMode; - contentWindow.__REACT_DEVTOOLS_DISABLE_SECOND_CONSOLE_LOG_DIMMING_IN_STRICT_MODE__ = - disableSecondConsoleLogDimmingInStrictMode; // TRICKY // The backend entry point may be required in the context of an iframe or the parent window. @@ -49,15 +35,7 @@ function startActivation(contentWindow: any, bridge: BackendBridge) { // Technically we don't need to store them on the contentWindow in this case, // but it doesn't really hurt anything to store them there too. if (contentWindow !== window) { - window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack; - window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = breakOnConsoleErrors; window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters; - window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = - showInlineWarningsAndErrors; - window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = - hideConsoleLogsInStrictMode; - window.__REACT_DEVTOOLS_DISABLE_SECOND_CONSOLE_LOG_DIMMING_IN_STRICT_MODE__ = - disableSecondConsoleLogDimmingInStrictMode; } finishActivation(contentWindow, bridge); diff --git a/packages/react-devtools-shared/src/__tests__/setupTests.js b/packages/react-devtools-shared/src/__tests__/setupTests.js index 6efcefe2f74..5774a573b31 100644 --- a/packages/react-devtools-shared/src/__tests__/setupTests.js +++ b/packages/react-devtools-shared/src/__tests__/setupTests.js @@ -240,9 +240,6 @@ beforeEach(() => { setSavedComponentFilters(getDefaultComponentFilters()); global.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = getDefaultComponentFilters(); - // Also initialize inline warnings so that we can test them. - global.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = true; - installHook(global, { appendComponentStack: true, breakOnConsoleErrors: false, diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index bc2669fda51..af3a87b5968 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -191,7 +191,7 @@ type NativeStyleEditor_SetValueParams = { value: string, }; -type SavedPreferencesParams = { +export type SavedPreferencesParams = { componentFilters: Array, }; diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 995f0da37ec..940e6c3374f 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -321,6 +321,74 @@ describe('ReactFlightDOMEdge', () => { expect(result).toEqual('Client Component'); }); + it('should resolve cyclic references in client component props after two rounds of serialization and deserialization', async () => { + const ClientComponent = clientExports(function ClientComponent({data}) { + return ( +
{data.self === data ? 'Cycle resolved' : 'Cycle broken'}
+ ); + }); + const clientModuleMetadata = webpackMap[ClientComponent.$$id]; + const consumerModuleId = 'consumer-' + clientModuleMetadata.id; + const clientReference = Object.defineProperties(ClientComponent, { + $$typeof: {value: Symbol.for('react.client.reference')}, + $$id: {value: ClientComponent.$$id}, + }); + webpackModules[consumerModuleId] = clientReference; + + const cyclic = {self: null}; + cyclic.self = cyclic; + + const stream1 = ReactServerDOMServer.renderToReadableStream( + + + , + webpackMap, + ); + + const promise = ReactServerDOMClient.createFromReadableStream(stream1, { + serverConsumerManifest: { + moduleMap: { + [clientModuleMetadata.id]: { + '*': { + id: consumerModuleId, + chunks: [], + name: '*', + }, + }, + }, + moduleLoading: webpackModuleLoading, + serverModuleMap: null, + }, + }); + + const errors = []; + const stream2 = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(promise, webpackMap, { + onError(error) { + errors.push(error); + }, + }), + ); + + expect(errors).toEqual([]); + + const element = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream2, { + serverConsumerManifest: { + moduleMap: null, + moduleLoading: null, + }, + }), + ); + + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(element), + ); + const result = await readResult(ssrStream); + + expect(result).toBe('
Cycle resolved
'); + }); + it('should be able to load a server reference on a consuming server if a mapping exists', async () => { function greet(name) { return 'hi, ' + name; diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 021913636bd..1f9bb0a77fa 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3622,8 +3622,8 @@ function renderModelDestructive( return renderModelDestructive( request, task, - emptyRoot, - '', + parent, + parentPropertyName, resolvedModel, ); }