Skip to content
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
},
"scripts": {
"build": "node ./scripts/rollup/build-all-release-channels.js",
"build-for-devtools": "cross-env RELEASE_CHANNEL=experimental yarn build react/index,react/jsx,react-dom/index,react-dom/client,react-dom/unstable_testing,react-dom/test-utils,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh,react-art --type=NODE",
"build-for-devtools": "cross-env RELEASE_CHANNEL=experimental yarn build react/index,react/jsx,react/compiler-runtime,react-dom/index,react-dom/client,react-dom/unstable_testing,react-dom/test-utils,react-is,react-debug-tools,scheduler,react-test-renderer,react-refresh,react-art --type=NODE",
"build-for-devtools-dev": "yarn build-for-devtools --type=NODE_DEV",
"build-for-devtools-prod": "yarn build-for-devtools --type=NODE_PROD",
"linc": "node ./scripts/tasks/linc.js",
Expand Down Expand Up @@ -137,6 +137,7 @@
"flags": "node ./scripts/flags/flags.js"
},
"resolutions": {
"react-is": "npm:react-is"
"react-is": "npm:react-is",
"jsdom": "22.1.0"
}
}
65 changes: 49 additions & 16 deletions packages/react-client/src/ReactFlightReplyClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export function processReply(
return '$' + tag + blobId.toString(16);
}

function serializeReadableStream(stream: ReadableStream): string {
function serializeBinaryReader(reader: any): string {
if (formData === null) {
// Upgrade to use FormData to allow us to stream this value.
formData = new FormData();
Expand All @@ -218,23 +218,43 @@ export function processReply(
pendingParts++;
const streamId = nextPartId++;

// Detect if this is a BYOB stream. BYOB streams should be able to be read as bytes on the
// receiving side. It also implies that different chunks can be split up or merged as opposed
// to a readable stream that happens to have Uint8Array as the type which might expect it to be
// received in the same slices.
// $FlowFixMe: This is a Node.js extension.
let supportsBYOB: void | boolean = stream.supportsBYOB;
if (supportsBYOB === undefined) {
try {
// $FlowFixMe[extra-arg]: This argument is accepted.
stream.getReader({mode: 'byob'}).releaseLock();
supportsBYOB = true;
} catch (x) {
supportsBYOB = false;
const buffer = [];

function progress(entry: {done: boolean, value: ReactServerValue, ...}) {
if (entry.done) {
const blobId = nextPartId++;
// eslint-disable-next-line react-internal/safe-string-coercion
data.append(formFieldPrefix + blobId, new Blob(buffer));
// eslint-disable-next-line react-internal/safe-string-coercion
data.append(
formFieldPrefix + streamId,
'"$o' + blobId.toString(16) + '"',
);
// eslint-disable-next-line react-internal/safe-string-coercion
data.append(formFieldPrefix + streamId, 'C'); // Close signal
pendingParts--;
if (pendingParts === 0) {
resolve(data);
}
} else {
buffer.push(entry.value);
reader.read(new Uint8Array(1024)).then(progress, reject);
}
}
reader.read(new Uint8Array(1024)).then(progress, reject);

const reader = stream.getReader();
return '$r' + streamId.toString(16);
}

function serializeReader(reader: ReadableStreamReader): string {
if (formData === null) {
// Upgrade to use FormData to allow us to stream this value.
formData = new FormData();
}
const data = formData;

pendingParts++;
const streamId = nextPartId++;

function progress(entry: {done: boolean, value: ReactServerValue, ...}) {
if (entry.done) {
Expand All @@ -258,7 +278,20 @@ export function processReply(
}
reader.read().then(progress, reject);

return '$' + (supportsBYOB ? 'r' : 'R') + streamId.toString(16);
return '$R' + streamId.toString(16);
}

function serializeReadableStream(stream: ReadableStream): string {
// Detect if this is a BYOB stream. BYOB streams should be able to be read as bytes on the
// receiving side. For binary streams, we serialize them as plain Blobs.
let binaryReader;
try {
// $FlowFixMe[extra-arg]: This argument is accepted.
binaryReader = stream.getReader({mode: 'byob'});
} catch (x) {
return serializeReader(stream.getReader());
}
return serializeBinaryReader(binaryReader);
}

function serializeAsyncIterable(
Expand Down
4 changes: 0 additions & 4 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,6 @@ describe('ReactFlight', () => {
expect(errors).toEqual([]);
});

// @gate enableServerComponentKeys
it('preserves state when keying a server component', async () => {
function StatefulClient({name}) {
const [state] = React.useState(name.toLowerCase());
Expand Down Expand Up @@ -1751,7 +1750,6 @@ describe('ReactFlight', () => {
);
});

// @gate enableServerComponentKeys
it('does not inherit keys of children inside a server component', async () => {
function StatefulClient({name, initial}) {
const [state] = React.useState(initial);
Expand Down Expand Up @@ -1824,7 +1822,6 @@ describe('ReactFlight', () => {
);
});

// @gate enableServerComponentKeys
it('shares state between single return and array return in a parent', async () => {
function StatefulClient({name, initial}) {
const [state] = React.useState(initial);
Expand Down Expand Up @@ -2065,7 +2062,6 @@ describe('ReactFlight', () => {
);
});

// @gate enableServerComponentKeys
it('preserves state with keys split across async work', async () => {
let resolve;
const promise = new Promise(r => (resolve = r));
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-devtools-core",
"version": "5.1.0",
"version": "5.2.0",
"description": "Use react-devtools outside of the browser",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 3,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Chrome Developer Tools.",
"version": "5.1.0",
"version_name": "5.1.0",
"version": "5.2.0",
"version_name": "5.2.0",
"minimum_chrome_version": "102",
"icons": {
"16": "icons/16-production.png",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/edge/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 3,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Microsoft Edge Developer Tools.",
"version": "5.1.0",
"version_name": "5.1.0",
"version": "5.2.0",
"version_name": "5.2.0",
"minimum_chrome_version": "102",
"icons": {
"16": "icons/16-production.png",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-extensions/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "React Developer Tools",
"description": "Adds React debugging tools to the Firefox Developer Tools.",
"version": "5.1.0",
"version": "5.2.0",
"applications": {
"gecko": {
"id": "@react-devtools",
Expand Down
49 changes: 31 additions & 18 deletions packages/react-devtools-fusebox/src/frontend.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,49 @@
* LICENSE file in the root directory of this source tree.
*/

export type MessagePayload =
| null
| string
| number
| boolean
| {[key: string]: MessagePayload}
| MessagePayload[];
export type Message = {event: string; payload?: MessagePayload};
export type MessagePayload = null | string | number | boolean | { [key: string]: MessagePayload } | MessagePayload[];
export type Message = { event: string, payload?: MessagePayload };

export type WallListener = (message: Message) => void;
export type Wall = {
listen: (fn: WallListener) => Function;
send: (event: string, payload?: MessagePayload) => void;
listen: (fn: WallListener) => Function,
send: (event: string, payload?: MessagePayload) => void,
};

export type Bridge = {
shutdown: () => void;
shutdown: () => void,
};
export type Store = Object;
export type BrowserTheme = 'dark' | 'light';

export function createBridge(wall: Wall): Bridge;
export function createStore(bridge: Bridge): Store;

export type Source = {
sourceURL: string,
line: number,
column: number,
};
export type ViewElementSource = (
source: Source,
symbolicatedSource: Source | null,
) => void;
export type ViewAttributeSource = (
id: number,
path: Array<string | number>,
) => void;
export type CanViewElementSource = (
source: Source,
symbolicatedSource: Source | null,
) => boolean;

export type InitializationOptions = {
bridge: Bridge;
store: Store;
theme?: BrowserTheme;
bridge: Bridge,
store: Store,
theme?: BrowserTheme,
viewAttributeSourceFunction?: ViewAttributeSource,
viewElementSourceFunction?: ViewElementSource,
canViewElementSourceFunction?: CanViewElementSource,
};
export function initialize(
node: Element | Document,
options: InitializationOptions,
): void;

export function initialize(node: Element | Document, options: InitializationOptions): void;
20 changes: 19 additions & 1 deletion packages/react-devtools-fusebox/src/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import type {
Wall,
} from 'react-devtools-shared/src/frontend/types';
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type {
ViewAttributeSource,
ViewElementSource,
CanViewElementSource,
} from 'react-devtools-shared/src/devtools/views/DevTools';

type Config = {
checkBridgeProtocolCompatibility?: boolean,
Expand Down Expand Up @@ -46,13 +51,23 @@ type InitializationOptions = {
bridge: FrontendBridge,
store: Store,
theme?: BrowserTheme,
viewAttributeSourceFunction?: ViewAttributeSource,
viewElementSourceFunction?: ViewElementSource,
canViewElementSourceFunction?: CanViewElementSource,
};

export function initialize(
contentWindow: Element | Document,
options: InitializationOptions,
): void {
const {bridge, store, theme = 'light'} = options;
const {
bridge,
store,
theme = 'light',
viewAttributeSourceFunction,
viewElementSourceFunction,
canViewElementSourceFunction,
} = options;
const root = createRoot(contentWindow);

root.render(
Expand All @@ -63,6 +78,9 @@ export function initialize(
showTabBar={true}
warnIfLegacyBackendDetected={true}
enabledInspectedElementContextMenu={true}
viewAttributeSourceFunction={viewAttributeSourceFunction}
viewElementSourceFunction={viewElementSourceFunction}
canViewElementSourceFunction={canViewElementSourceFunction}
/>,
);
}
2 changes: 1 addition & 1 deletion packages/react-devtools-inline/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-devtools-inline",
"version": "5.1.0",
"version": "5.2.0",
"description": "Embed react-devtools within a website",
"license": "MIT",
"main": "./dist/backend.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ describe('profiling charts', () => {
"actualDuration": 0,
"didRender": true,
"id": 5,
"label": "Memo(Child) key="third" (<0.1ms of <0.1ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="third" (<0.1ms of <0.1ms)",
"name": "Child",
"offset": 15,
"selfDuration": 0,
"treeBaseDuration": 0,
Expand All @@ -134,8 +134,8 @@ describe('profiling charts', () => {
"actualDuration": 2,
"didRender": true,
"id": 4,
"label": "Memo(Child) key="second" (2ms of 2ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="second" (2ms of 2ms)",
"name": "Child",
"offset": 13,
"selfDuration": 2,
"treeBaseDuration": 2,
Expand All @@ -144,8 +144,8 @@ describe('profiling charts', () => {
"actualDuration": 3,
"didRender": true,
"id": 3,
"label": "Memo(Child) key="first" (3ms of 3ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="first" (3ms of 3ms)",
"name": "Child",
"offset": 10,
"selfDuration": 3,
"treeBaseDuration": 3,
Expand Down Expand Up @@ -175,8 +175,8 @@ describe('profiling charts', () => {
"actualDuration": 0,
"didRender": false,
"id": 5,
"label": "Memo(Child) key="third"",
"name": "Memo(Child)",
"label": "Child (Memo) key="third"",
"name": "Child",
"offset": 15,
"selfDuration": 0,
"treeBaseDuration": 0,
Expand All @@ -185,8 +185,8 @@ describe('profiling charts', () => {
"actualDuration": 0,
"didRender": false,
"id": 4,
"label": "Memo(Child) key="second"",
"name": "Memo(Child)",
"label": "Child (Memo) key="second"",
"name": "Child",
"offset": 13,
"selfDuration": 0,
"treeBaseDuration": 2,
Expand All @@ -195,8 +195,8 @@ describe('profiling charts', () => {
"actualDuration": 0,
"didRender": false,
"id": 3,
"label": "Memo(Child) key="first"",
"name": "Memo(Child)",
"label": "Child (Memo) key="first"",
"name": "Child",
"offset": 10,
"selfDuration": 0,
"treeBaseDuration": 3,
Expand Down Expand Up @@ -264,20 +264,20 @@ describe('profiling charts', () => {
},
{
"id": 3,
"label": "Memo(Child) (Memo) key="first" (3ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="first" (3ms)",
"name": "Child",
"value": 3,
},
{
"id": 4,
"label": "Memo(Child) (Memo) key="second" (2ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="second" (2ms)",
"name": "Child",
"value": 2,
},
{
"id": 5,
"label": "Memo(Child) (Memo) key="third" (<0.1ms)",
"name": "Memo(Child)",
"label": "Child (Memo) key="third" (<0.1ms)",
"name": "Child",
"value": 0,
},
]
Expand Down
Loading