Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export * from 'react-client/src/ReactFlightClientHostConfigBrowser';
export * from 'react-client/src/ReactFlightClientHostConfigStream';
export * from 'react-server-dom-webpack/src/ReactFlightClientWebpackBundlerConfig';
80 changes: 80 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerNext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {ReactNodeList} from 'shared/ReactTypes';
import type {Destination} from 'react-server/src/ReactServerStreamConfigNext';

import ReactVersion from 'shared/ReactVersion';

import {
createRequest,
startWork,
startFlowing,
stopFlowing,
abort,
} from 'react-server/src/ReactFizzServer';

import {
createResponseState,
createRootFormatContext,
} from './ReactDOMServerFormatConfig';

type Options = {|
identifierPrefix?: string,
namespaceURI?: string,
progressiveChunkSize?: number,
onReadyToStream?: () => void,
onCompleteAll?: () => void,
onError?: (error: mixed) => void,
|};

type Controls = {|
abort(): void,
startWriting(): void,
stopWriting(): void,
|};

function createRequestImpl(
children: ReactNodeList,
destination: Destination,
options: void | Options,
) {
return createRequest(
children,
destination,
createResponseState(options ? options.identifierPrefix : undefined),
createRootFormatContext(options ? options.namespaceURI : undefined),
options ? options.progressiveChunkSize : undefined,
options ? options.onError : undefined,
options ? options.onCompleteAll : undefined,
options ? options.onReadyToStream : undefined,
);
}

function renderToNextStream(
children: ReactNodeList,
destination: Destination,
options?: Options,
): Controls {
const request = createRequestImpl(children, destination, options);
startWork(request);
return {
abort() {
abort(request);
},
startWriting() {
startFlowing(request);
},
stopWriting() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was planning on renaming startWriting so naming this as a pair wouldn't necessarily make sense.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure what you mean. Would a single function to toggle on/off be better? Or otherwise could you elaborate?

stopFlowing(request);
},
};
}

export {renderToNextStream, ReactVersion as version};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type Destination = {
export type PrecomputedChunk = string;
export type Chunk = string;

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
callback();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/react-noop-renderer/src/ReactNoopServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const POP = Buffer.from('/', 'utf8');
let opaqueID = 0;

const ReactNoopServer = ReactFizzServer({
scheduleWork(callback: () => void) {
scheduleWork(destination: Destination, callback: () => void) {
callback();
},
beginWriting(destination: Destination): void {},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export * from 'react-dom/src/client/ReactDOMHostConfig';
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export function processSymbolChunk(
return ['S', id, name];
}

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
callback();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type Destination = {
export type PrecomputedChunk = string;
export type Chunk = string;

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
// We don't schedule work in this model, and instead expect performWork to always be called repeatedly.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export function processSymbolChunk(
return ['S', id, name];
}

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
callback();
}

Expand Down
11 changes: 9 additions & 2 deletions packages/react-server/src/ReactFizzServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ function pingTask(request: Request, task: Task): void {
const pingedTasks = request.pingedTasks;
pingedTasks.push(task);
if (pingedTasks.length === 1) {
scheduleWork(() => performWork(request));
scheduleWork(request.destination, () => performWork(request));
}
}

Expand Down Expand Up @@ -1899,7 +1899,7 @@ function flushCompletedQueues(request: Request): void {
}

export function startWork(request: Request): void {
scheduleWork(() => performWork(request));
scheduleWork(request.destination, () => performWork(request));
Copy link
Copy Markdown
Contributor

@sebmarkbage sebmarkbage Sep 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it might make sense to want to schedule based on the destination, the assumption of this API implies a lot more of a global scheduler like postTask. I worry that this might take us down the wrong assumptions.

For sync I/O, it'll also be required that it's an instance (or at least thread) per request so in that world it doesn't matter anyway.

What is the intention/purpose of this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh, just some flexibility. I can revert it and make it use a global instead, that wouldn't be a problem.

}

export function startFlowing(request: Request): void {
Expand All @@ -1915,6 +1915,13 @@ export function startFlowing(request: Request): void {
}
}

export function stopFlowing(request: Request): void {
if (request.status === CLOSED) {
return;
}
request.status = BUFFERING;
}

// This is called to early terminate a request. It puts all pending boundaries in client rendered state.
export function abort(request: Request): void {
try {
Expand Down
4 changes: 2 additions & 2 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ function pingSegment(request: Request, segment: Segment): void {
const pingedSegments = request.pingedSegments;
pingedSegments.push(segment);
if (pingedSegments.length === 1) {
scheduleWork(() => performWork(request));
scheduleWork(request.destination, () => performWork(request));
}
}

Expand Down Expand Up @@ -768,7 +768,7 @@ function flushCompletedChunks(request: Request): void {

export function startWork(request: Request): void {
request.flowing = true;
scheduleWork(() => performWork(request));
scheduleWork(request.destination, () => performWork(request));
}

export function startFlowing(request: Request): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type Destination = ReadableStreamController;
export type PrecomputedChunk = Uint8Array;
export type Chunk = Uint8Array;

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
callback();
}

Expand Down
62 changes: 62 additions & 0 deletions packages/react-server/src/ReactServerStreamConfigNext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export type Destination = {
write: (chunk: Uint8Array) => void,
buffer: (shouldBuffer: boolean) => void,
flush: () => void,
close: (error: mixed) => void,
schedule: (callback: () => void) => void,
ready: boolean,
};

export type PrecomputedChunk = Uint8Array;
export type Chunk = Uint8Array;

export function scheduleWork(destination: Destination, callback: () => void) {
destination.schedule(callback);
}

export function flushBuffered(destination: Destination) {
destination.flush();
}

export function beginWriting(destination: Destination) {
destination.buffer(true);
}

export function writeChunk(
destination: Destination,
chunk: PrecomputedChunk | Chunk,
): boolean {
destination.write(chunk);
return destination.ready;
}

export function completeWriting(destination: Destination) {
destination.buffer(false);
}

export function close(destination: Destination) {
destination.close();
}

const textEncoder = new TextEncoder();

export function stringToChunk(content: string): Chunk {
return textEncoder.encode(content);
}

export function stringToPrecomputedChunk(content: string): PrecomputedChunk {
return textEncoder.encode(content);
}

export function closeWithError(destination: Destination, error: mixed): void {
destination.close(error);
}
2 changes: 1 addition & 1 deletion packages/react-server/src/ReactServerStreamConfigNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type Destination = Writable & MightBeFlushable;
export type PrecomputedChunk = Uint8Array;
export type Chunk = string;

export function scheduleWork(callback: () => void) {
export function scheduleWork(destination: Destination, callback: () => void) {
setImmediate(callback);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export * from '../ReactFlightServerConfigStream';
export * from 'react-server-dom-webpack/src/ReactFlightServerWebpackBundlerConfig';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export * from 'react-dom/src/server/ReactDOMServerFormatConfig';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export * from '../ReactServerStreamConfigNext';
8 changes: 8 additions & 0 deletions scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,14 @@ const bundles = [
global: 'ReactDOMServer',
externals: ['react'],
},
{
bundleTypes: [NODE_DEV, NODE_PROD],
moduleType: RENDERER,
entry: 'react-dom/src/server/ReactDOMFizzServerNext',
name: 'react-dom-server-next',
global: 'ReactDOMServer',
externals: ['react'],
},
{
bundleTypes: __EXPERIMENTAL__ ? [FB_WWW_DEV, FB_WWW_PROD] : [],
moduleType: RENDERER,
Expand Down
11 changes: 11 additions & 0 deletions scripts/shared/inlinedHostConfigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ module.exports = [
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'dom-next',
entryPoints: [
'react-dom/src/server/ReactDOMFizzServerNext', // react-dom/server
],
paths: [
'react-dom/src/server/ReactDOMFizzServerNext.js', // react-dom/server.browser
],
isFlowTyped: true,
isServerSupported: true,
},
{
shortName: 'art',
entryPoints: ['react-art'],
Expand Down