diff --git a/packages/react-client/src/forks/ReactFlightClientHostConfig.dom-legacy.js b/packages/react-client/src/forks/ReactFlightClientHostConfig.dom-legacy.js new file mode 100644 index 00000000000000..59e1171c144eae --- /dev/null +++ b/packages/react-client/src/forks/ReactFlightClientHostConfig.dom-legacy.js @@ -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'; diff --git a/packages/react-dom/server.browser.classic.fb.js b/packages/react-dom/server.browser.classic.fb.js new file mode 100644 index 00000000000000..c57063649a9f01 --- /dev/null +++ b/packages/react-dom/server.browser.classic.fb.js @@ -0,0 +1,16 @@ +/** + * 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 { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerBrowser'; diff --git a/packages/react-dom/server.browser.js b/packages/react-dom/server.browser.js index c57063649a9f01..bd63acc8685f7d 100644 --- a/packages/react-dom/server.browser.js +++ b/packages/react-dom/server.browser.js @@ -13,4 +13,4 @@ export { renderToNodeStream, renderToStaticNodeStream, version, -} from './src/server/ReactDOMServerBrowser'; +} from './src/server/ReactDOMLegacyServerBrowser'; diff --git a/packages/react-dom/server.browser.stable.js b/packages/react-dom/server.browser.stable.js new file mode 100644 index 00000000000000..c57063649a9f01 --- /dev/null +++ b/packages/react-dom/server.browser.stable.js @@ -0,0 +1,16 @@ +/** + * 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 { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerBrowser'; diff --git a/packages/react-dom/server.node.classic.fb.js b/packages/react-dom/server.node.classic.fb.js new file mode 100644 index 00000000000000..e610a8818f961b --- /dev/null +++ b/packages/react-dom/server.node.classic.fb.js @@ -0,0 +1,17 @@ +/** + * 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 + */ + +// For some reason Flow doesn't like export * in this file. I don't know why. +export { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerNode'; diff --git a/packages/react-dom/server.node.js b/packages/react-dom/server.node.js index e610a8818f961b..92b69c03bc34e3 100644 --- a/packages/react-dom/server.node.js +++ b/packages/react-dom/server.node.js @@ -14,4 +14,4 @@ export { renderToNodeStream, renderToStaticNodeStream, version, -} from './src/server/ReactDOMServerNode'; +} from './src/server/ReactDOMLegacyServerNode'; diff --git a/packages/react-dom/server.node.stable.js b/packages/react-dom/server.node.stable.js new file mode 100644 index 00000000000000..e610a8818f961b --- /dev/null +++ b/packages/react-dom/server.node.stable.js @@ -0,0 +1,17 @@ +/** + * 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 + */ + +// For some reason Flow doesn't like export * in this file. I don't know why. +export { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerNode'; diff --git a/packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js b/packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js new file mode 100644 index 00000000000000..2ea0b22d10abca --- /dev/null +++ b/packages/react-dom/src/server/ReactDOMLegacyServerBrowser.js @@ -0,0 +1,97 @@ +/** + * 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 ReactVersion from 'shared/ReactVersion'; +import invariant from 'shared/invariant'; + +import type {ReactNodeList} from 'shared/ReactTypes'; + +import { + createRequest, + startWork, + startFlowing, + abort, +} from 'react-server/src/ReactFizzServer'; + +import { + createResponseState, + createRootFormatContext, +} from './ReactDOMServerFormatConfig'; + +type ServerOptions = { + identifierPrefix?: string, +}; + +function onError() { + // Non-fatal errors are ignored. +} + +function renderToString( + children: ReactNodeList, + options?: ServerOptions, +): string { + let didFatal = false; + let fatalError = null; + const result = []; + const destination = { + push(chunk) { + if (chunk) { + result.push(chunk); + } + return true; + }, + destroy(error) { + didFatal = true; + fatalError = error; + }, + }; + const request = createRequest( + children, + destination, + createResponseState(options ? options.identifierPrefix : undefined), + createRootFormatContext(undefined), + Infinity, + onError, + undefined, + undefined, + ); + startWork(request); + // If anything suspended and is still pending, we'll abort it before writing. + // That way we write only client-rendered boundaries from the start. + abort(request); + startFlowing(request); + if (didFatal) { + throw fatalError; + } + return result.join(''); +} + +function renderToNodeStream() { + invariant( + false, + 'ReactDOMServer.renderToNodeStream(): The streaming API is not available ' + + 'in the browser. Use ReactDOMServer.renderToString() instead.', + ); +} + +function renderToStaticNodeStream() { + invariant( + false, + 'ReactDOMServer.renderToStaticNodeStream(): The streaming API is not available ' + + 'in the browser. Use ReactDOMServer.renderToStaticMarkup() instead.', + ); +} + +export { + renderToString, + renderToString as renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + ReactVersion as version, +}; diff --git a/packages/react-dom/src/server/ReactDOMLegacyServerNode.js b/packages/react-dom/src/server/ReactDOMLegacyServerNode.js new file mode 100644 index 00000000000000..29ba74f8ffaf77 --- /dev/null +++ b/packages/react-dom/src/server/ReactDOMLegacyServerNode.js @@ -0,0 +1,98 @@ +/** + * 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 {Request} from 'react-server/src/ReactFizzServer'; + +import { + createRequest, + startWork, + startFlowing, + abort, +} from 'react-server/src/ReactFizzServer'; + +import { + createResponseState, + createRootFormatContext, +} from './ReactDOMServerFormatConfig'; + +import { + version, + renderToString, + renderToStaticMarkup, +} from './ReactDOMLegacyServerBrowser'; + +import {Readable} from 'stream'; + +type ServerOptions = { + identifierPrefix?: string, +}; + +class ReactMarkupReadableStream extends Readable { + request: Request; + startedFlowing: boolean; + constructor() { + // Calls the stream.Readable(options) constructor. Consider exposing built-in + // features like highWaterMark in the future. + super({}); + this.request = (null: any); + this.startedFlowing = false; + } + + _destroy(err, callback) { + abort(this.request); + // $FlowFixMe: The type definition for the callback should allow undefined and null. + callback(err); + } + + _read(size) { + if (this.startedFlowing) { + startFlowing(this.request); + } + } +} + +function onError() { + // Non-fatal errors are ignored. +} + +function renderToNodeStream( + children: ReactNodeList, + options?: ServerOptions, +): Readable { + function onCompleteAll() { + // We wait until everything has loaded before starting to write. + // That way we only end up with fully resolved HTML even if we suspend. + destination.startedFlowing = true; + startFlowing(request); + } + const destination = new ReactMarkupReadableStream(); + const request = createRequest( + children, + destination, + createResponseState(options ? options.identifierPrefix : undefined), + createRootFormatContext(undefined), + Infinity, + onError, + onCompleteAll, + undefined, + ); + destination.request = request; + startWork(request); + return destination; +} + +export { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToNodeStream as renderToStaticNodeStream, + version, +}; diff --git a/packages/react-dom/src/server/ReactDOMLegacyServerStreamConfig.js b/packages/react-dom/src/server/ReactDOMLegacyServerStreamConfig.js new file mode 100644 index 00000000000000..d32808f2bcec40 --- /dev/null +++ b/packages/react-dom/src/server/ReactDOMLegacyServerStreamConfig.js @@ -0,0 +1,51 @@ +/** + * 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 = { + push(chunk: string | null): boolean, + destroy(error: Error): mixed, + ... +}; + +export type PrecomputedChunk = string; +export type Chunk = string; + +export function scheduleWork(callback: () => void) { + callback(); +} + +export function flushBuffered(destination: Destination) {} + +export function beginWriting(destination: Destination) {} + +export function writeChunk( + destination: Destination, + chunk: Chunk | PrecomputedChunk, +): boolean { + return destination.push(chunk); +} + +export function completeWriting(destination: Destination) {} + +export function close(destination: Destination) { + destination.push(null); +} + +export function stringToChunk(content: string): Chunk { + return content; +} + +export function stringToPrecomputedChunk(content: string): PrecomputedChunk { + return content; +} + +export function closeWithError(destination: Destination, error: mixed): void { + // $FlowFixMe: This is an Error object or the destination accepts other types. + destination.destroy(error); +} diff --git a/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-legacy.js b/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-legacy.js new file mode 100644 index 00000000000000..d830c8501be277 --- /dev/null +++ b/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-legacy.js @@ -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'; diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index a27a845f422e75..f4cdb0edd965ed 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -161,7 +161,7 @@ const BUFFERING = 0; const FLOWING = 1; const CLOSED = 2; -type Request = { +export opaque type Request = { +destination: Destination, +responseState: ResponseState, +progressiveChunkSize: number, diff --git a/packages/react-server/src/forks/ReactFlightServerConfig.dom-legacy.js b/packages/react-server/src/forks/ReactFlightServerConfig.dom-legacy.js new file mode 100644 index 00000000000000..07b5f345f19363 --- /dev/null +++ b/packages/react-server/src/forks/ReactFlightServerConfig.dom-legacy.js @@ -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'; diff --git a/packages/react-server/src/forks/ReactServerFormatConfig.dom-legacy.js b/packages/react-server/src/forks/ReactServerFormatConfig.dom-legacy.js new file mode 100644 index 00000000000000..c6e482efeb60c4 --- /dev/null +++ b/packages/react-server/src/forks/ReactServerFormatConfig.dom-legacy.js @@ -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'; diff --git a/packages/react-server/src/forks/ReactServerStreamConfig.dom-legacy.js b/packages/react-server/src/forks/ReactServerStreamConfig.dom-legacy.js new file mode 100644 index 00000000000000..160efd5a92b23f --- /dev/null +++ b/packages/react-server/src/forks/ReactServerStreamConfig.dom-legacy.js @@ -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/ReactDOMLegacyServerStreamConfig'; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index e37e7bbfe644a9..cffde35c448d9c 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -246,7 +246,7 @@ const bundles = [ FB_WWW_DEV, FB_WWW_PROD, ], - moduleType: NON_FIBER_RENDERER, + moduleType: __EXPERIMENTAL__ ? RENDERER : NON_FIBER_RENDERER, entry: 'react-dom/server.browser', global: 'ReactDOMServer', externals: ['react'], @@ -259,7 +259,7 @@ const bundles = [ }, { bundleTypes: [NODE_DEV, NODE_PROD], - moduleType: NON_FIBER_RENDERER, + moduleType: __EXPERIMENTAL__ ? RENDERER : NON_FIBER_RENDERER, entry: 'react-dom/server.node', externals: ['react', 'stream'], babel: opts => diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js index 7f96ae163ad63c..8b95312bee2bf5 100644 --- a/scripts/shared/inlinedHostConfigs.js +++ b/scripts/shared/inlinedHostConfigs.js @@ -20,6 +20,7 @@ module.exports = [ 'react-dom', 'react-dom/unstable-fizz', 'react-dom/unstable-fizz.node', + 'react-dom/server.node.stable', 'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/unstable-fizz.node 'react-server-dom-webpack', 'react-server-dom-webpack/writer', @@ -44,6 +45,7 @@ module.exports = [ 'react-dom', 'react-dom/testing', 'react-dom/unstable-fizz.browser', + 'react-dom/server.browser.stable', 'react-dom/src/server/ReactDOMFizzServerBrowser.js', // react-dom/unstable-fizz.browser 'react-server-dom-webpack', 'react-server-dom-webpack/writer.browser.server', @@ -53,6 +55,22 @@ module.exports = [ isFlowTyped: true, isServerSupported: true, }, + { + shortName: 'dom-legacy', + entryPoints: ['react-dom/server.browser', 'react-dom/server.node'], + paths: [ + 'react-dom', + 'react-dom/server', + 'react-dom/server.browser', + 'react-dom/server.node', + 'react-server-dom-webpack', + 'react-dom/src/server/ReactDOMLegacyServerBrowser.js', // react-dom/server.browser + 'react-dom/src/server/ReactDOMLegacyServerNode.js', // react-dom/server.node + 'react-client/src/ReactFlightClientStream.js', // We can only type check this in streaming configurations. + ], + isFlowTyped: true, + isServerSupported: true, + }, { shortName: 'art', entryPoints: ['react-art'],