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
48 changes: 29 additions & 19 deletions packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,11 @@ export type FindSourceMapURLCallback = (

export type DebugChannelCallback = (message: string) => void;

export type DebugChannel = {
hasReadable: boolean,
callback: DebugChannelCallback | null,
};

type Response = {
_bundlerConfig: ServerConsumerModuleMap,
_serverReferenceConfig: null | ServerManifest,
Expand All @@ -362,7 +367,7 @@ type Response = {
_debugRootStack?: null | Error, // DEV-only
_debugRootTask?: null | ConsoleTask, // DEV-only
_debugFindSourceMapURL?: void | FindSourceMapURLCallback, // DEV-only
_debugChannel?: void | DebugChannelCallback, // DEV-only
_debugChannel?: void | DebugChannel, // DEV-only
_blockedConsole?: null | SomeChunk<ConsoleEntry>, // DEV-only
_replayConsole: boolean, // DEV-only
_rootEnvironmentName: string, // DEV-only, the requested environment name.
Expand Down Expand Up @@ -404,16 +409,16 @@ function getWeakResponse(response: Response): WeakResponse {
}
}

function cleanupDebugChannel(debugChannel: DebugChannelCallback): void {
// When a Response gets GC:ed because nobody is referring to any of the objects that lazily
// loads from the Response anymore, then we can close the debug channel.
debugChannel('');
function closeDebugChannel(debugChannel: DebugChannel): void {
if (debugChannel.callback) {
debugChannel.callback('');
}
}

// If FinalizationRegistry doesn't exist, we cannot use the debugChannel.
const debugChannelRegistry =
__DEV__ && typeof FinalizationRegistry === 'function'
? new FinalizationRegistry(cleanupDebugChannel)
? new FinalizationRegistry(closeDebugChannel)
: null;

function readChunk<T>(chunk: SomeChunk<T>): T {
Expand Down Expand Up @@ -1007,7 +1012,7 @@ export function reportGlobalError(
if (debugChannel !== undefined) {
// If we don't have any more ways of reading data, we don't have to send any
// more neither. So we close the writable side.
debugChannel('');
closeDebugChannel(debugChannel);
response._debugChannel = undefined;
}
}
Expand Down Expand Up @@ -1494,8 +1499,8 @@ function waitForReference<T>(
): T {
if (
__DEV__ &&
// TODO: This should check for the existence of the "readable" side, not the "writable".
response._debugChannel === undefined
(response._debugChannel === undefined ||
!response._debugChannel.hasReadable)
) {
if (
referencedChunk.status === PENDING &&
Expand Down Expand Up @@ -2262,15 +2267,16 @@ function parseModelString(
case 'Y': {
if (__DEV__) {
if (value.length > 2) {
const debugChannel = response._debugChannel;
if (debugChannel) {
const debugChannelCallback =
response._debugChannel && response._debugChannel.callback;
if (debugChannelCallback) {
if (value[2] === '@') {
// This is a deferred Promise.
const ref = value.slice(3); // We assume this doesn't have a path just id.
const id = parseInt(ref, 16);
if (!response._chunks.has(id)) {
// We haven't seen this id before. Query the server to start sending it.
debugChannel('P:' + ref);
debugChannelCallback('P:' + ref);
}
// Start waiting. This now creates a pending chunk if it doesn't already exist.
// This is the actual Promise we're waiting for.
Expand All @@ -2280,7 +2286,7 @@ function parseModelString(
const id = parseInt(ref, 16);
if (!response._chunks.has(id)) {
// We haven't seen this id before. Query the server to start sending it.
debugChannel('Q:' + ref);
debugChannelCallback('Q:' + ref);
}
// Start waiting. This now creates a pending chunk if it doesn't already exist.
const chunk = getChunk(response, id);
Expand Down Expand Up @@ -2358,7 +2364,7 @@ function ResponseInstance(
findSourceMapURL: void | FindSourceMapURLCallback, // DEV-only
replayConsole: boolean, // DEV-only
environmentName: void | string, // DEV-only
debugChannel: void | DebugChannelCallback, // DEV-only
debugChannel: void | DebugChannel, // DEV-only
) {
const chunks: Map<number, SomeChunk<any>> = new Map();
this._bundlerConfig = bundlerConfig;
Expand Down Expand Up @@ -2420,10 +2426,14 @@ function ResponseInstance(
this._rootEnvironmentName = rootEnv;
if (debugChannel) {
if (debugChannelRegistry === null) {
// We can't safely clean things up later, so we immediately close the debug channel.
debugChannel('');
// We can't safely clean things up later, so we immediately close the
// debug channel.
closeDebugChannel(debugChannel);
this._debugChannel = undefined;
} else {
// When a Response gets GC:ed because nobody is referring to any of the
// objects that lazily load from the Response anymore, then we can close
// the debug channel.
debugChannelRegistry.register(this, debugChannel);
}
}
Expand Down Expand Up @@ -2451,7 +2461,7 @@ export function createResponse(
findSourceMapURL: void | FindSourceMapURLCallback, // DEV-only
replayConsole: boolean, // DEV-only
environmentName: void | string, // DEV-only
debugChannel: void | DebugChannelCallback, // DEV-only
debugChannel: void | DebugChannel, // DEV-only
): WeakResponse {
return getWeakResponse(
// $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors
Expand Down Expand Up @@ -3545,8 +3555,8 @@ function resolveDebugModel(
if (
__DEV__ &&
((debugChunk: any): SomeChunk<any>).status === BLOCKED &&
// TODO: This should check for the existence of the "readable" side, not the "writable".
response._debugChannel === undefined
(response._debugChannel === undefined ||
!response._debugChannel.hasReadable)
) {
if (json[0] === '"' && json[1] === '$') {
const path = json.slice(2, json.length - 1).split(':');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
import type {Thenable} from 'shared/ReactTypes.js';

import type {
Response as FlightResponse,
FindSourceMapURLCallback,
DebugChannel,
DebugChannelCallback,
FindSourceMapURLCallback,
Response as FlightResponse,
} from 'react-client/src/ReactFlightClient';

import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
Expand Down Expand Up @@ -72,6 +73,19 @@ function createDebugCallbackFromWritableStream(
}

function createResponseFromOptions(options: void | Options) {
const debugChannel: void | DebugChannel =
__DEV__ && options && options.debugChannel !== undefined
? {
hasReadable: options.debugChannel.readable !== undefined,
callback:
options.debugChannel.writable !== undefined
? createDebugCallbackFromWritableStream(
options.debugChannel.writable,
)
: null,
}
: undefined;

return createResponse(
options && options.moduleBaseURL ? options.moduleBaseURL : '',
null,
Expand All @@ -89,12 +103,7 @@ function createResponseFromOptions(options: void | Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ &&
options &&
options.debugChannel !== undefined &&
options.debugChannel.writable !== undefined
? createDebugCallbackFromWritableStream(options.debugChannel.writable)
: undefined,
debugChannel,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import type {Thenable, ReactCustomFormAction} from 'shared/ReactTypes.js';

import type {
Response,
DebugChannel,
FindSourceMapURLCallback,
Response,
} from 'react-client/src/ReactFlightClient';

import type {Readable} from 'stream';
Expand Down Expand Up @@ -88,6 +89,14 @@ function createFromNodeStream<T>(
moduleBaseURL: string,
options?: Options,
): Thenable<T> {
const debugChannel: void | DebugChannel =
__DEV__ && options && options.debugChannel !== undefined
? {
hasReadable: options.debugChannel.readable !== undefined,
callback: null,
}
: undefined;

const response: Response = createResponse(
moduleRootPath,
null,
Expand All @@ -103,6 +112,7 @@ function createFromNodeStream<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
debugChannel,
);

if (__DEV__ && options && options.debugChannel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

import type {Thenable} from 'shared/ReactTypes.js';
import type {
Response as FlightResponse,
DebugChannel,
DebugChannelCallback,
Response as FlightResponse,
} from 'react-client/src/ReactFlightClient';
import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
import type {ServerReferenceId} from '../client/ReactFlightClientConfigBundlerParcel';
Expand Down Expand Up @@ -99,6 +100,39 @@ function createDebugCallbackFromWritableStream(
};
}

function createResponseFromOptions(options: void | Options) {
const debugChannel: void | DebugChannel =
__DEV__ && options && options.debugChannel !== undefined
? {
hasReadable: options.debugChannel.readable !== undefined,
callback:
options.debugChannel.writable !== undefined
? createDebugCallbackFromWritableStream(
options.debugChannel.writable,
)
: null,
}
: undefined;

return createResponse(
null, // bundlerConfig
null, // serverReferenceConfig
null, // moduleLoading
callCurrentServerCallback,
undefined, // encodeFormAction
undefined, // nonce
options && options.temporaryReferences
? options.temporaryReferences
: undefined,
__DEV__ ? findSourceMapURL : undefined,
__DEV__ ? (options ? options.replayConsoleLogs !== false : true) : false, // defaults to true
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
debugChannel,
);
}

function startReadingFromUniversalStream(
response: FlightResponse,
stream: ReadableStream,
Expand Down Expand Up @@ -176,28 +210,7 @@ export function createFromReadableStream<T>(
stream: ReadableStream,
options?: Options,
): Thenable<T> {
const response: FlightResponse = createResponse(
null, // bundlerConfig
null, // serverReferenceConfig
null, // moduleLoading
callCurrentServerCallback,
undefined, // encodeFormAction
undefined, // nonce
options && options.temporaryReferences
? options.temporaryReferences
: undefined,
__DEV__ ? findSourceMapURL : undefined,
__DEV__ ? (options ? options.replayConsoleLogs !== false : true) : false, // defaults to true
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ &&
options &&
options.debugChannel !== undefined &&
options.debugChannel.writable !== undefined
? createDebugCallbackFromWritableStream(options.debugChannel.writable)
: undefined,
);
const response: FlightResponse = createResponseFromOptions(options);
if (
__DEV__ &&
options &&
Expand Down Expand Up @@ -226,28 +239,7 @@ export function createFromFetch<T>(
promiseForResponse: Promise<Response>,
options?: Options,
): Thenable<T> {
const response: FlightResponse = createResponse(
null, // bundlerConfig
null, // serverReferenceConfig
null, // moduleLoading
callCurrentServerCallback,
undefined, // encodeFormAction
undefined, // nonce
options && options.temporaryReferences
? options.temporaryReferences
: undefined,
__DEV__ ? findSourceMapURL : undefined,
__DEV__ ? (options ? options.replayConsoleLogs !== false : true) : false, // defaults to true
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
__DEV__ &&
options &&
options.debugChannel !== undefined &&
options.debugChannel.writable !== undefined
? createDebugCallbackFromWritableStream(options.debugChannel.writable)
: undefined,
);
const response: FlightResponse = createResponseFromOptions(options);
promiseForResponse.then(
function (r) {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@

import type {Thenable, ReactCustomFormAction} from 'shared/ReactTypes.js';

import type {Response as FlightResponse} from 'react-client/src/ReactFlightClient';
import type {
DebugChannel,
Response as FlightResponse,
} from 'react-client/src/ReactFlightClient';
import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';

import {
Expand Down Expand Up @@ -81,6 +84,14 @@ export type Options = {
};

function createResponseFromOptions(options?: Options) {
const debugChannel: void | DebugChannel =
__DEV__ && options && options.debugChannel !== undefined
? {
hasReadable: options.debugChannel.readable !== undefined,
callback: null,
}
: undefined;

return createResponse(
null, // bundlerConfig
null, // serverReferenceConfig
Expand All @@ -96,6 +107,7 @@ function createResponseFromOptions(options?: Options) {
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
debugChannel,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import type {Thenable, ReactCustomFormAction} from 'shared/ReactTypes.js';
import type {Response} from 'react-client/src/ReactFlightClient';
import type {DebugChannel, Response} from 'react-client/src/ReactFlightClient';
import type {Readable} from 'stream';

import {
Expand Down Expand Up @@ -82,6 +82,14 @@ export function createFromNodeStream<T>(
stream: Readable,
options?: Options,
): Thenable<T> {
const debugChannel: void | DebugChannel =
__DEV__ && options && options.debugChannel !== undefined
? {
hasReadable: options.debugChannel.readable !== undefined,
callback: null,
}
: undefined;

const response: Response = createResponse(
null, // bundlerConfig
null, // serverReferenceConfig
Expand All @@ -95,6 +103,7 @@ export function createFromNodeStream<T>(
__DEV__ && options && options.environmentName
? options.environmentName
: undefined,
debugChannel,
);

if (__DEV__ && options && options.debugChannel) {
Expand Down
Loading
Loading