diff --git a/package.json b/package.json
index 9f3d3d0970d80..e3e37c428d4a1 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,8 @@
"targz": "^1.0.1",
"through2": "^2.0.0",
"tmp": "~0.0.28",
- "typescript": "~1.8.10"
+ "typescript": "~1.8.10",
+ "@mattiasbuelens/web-streams-polyfill": "0.1.0"
},
"devEngines": {
"node": "8.x || 9.x || 10.x"
diff --git a/packages/react-dom/npm/unstable-fizz.browser.js b/packages/react-dom/npm/unstable-fizz.browser.js
new file mode 100644
index 0000000000000..038a3fd0fb495
--- /dev/null
+++ b/packages/react-dom/npm/unstable-fizz.browser.js
@@ -0,0 +1,7 @@
+'use strict';
+
+if (process.env.NODE_ENV === 'production') {
+ module.exports = require('./cjs/react-dom-unstable-fizz.node.production.min.js');
+} else {
+ module.exports = require('./cjs/react-dom-unstable-fizz.node.development.js');
+}
diff --git a/packages/react-dom/npm/unstable-fizz.node.js b/packages/react-dom/npm/unstable-fizz.node.js
index 45babe4e00588..038a3fd0fb495 100644
--- a/packages/react-dom/npm/unstable-fizz.node.js
+++ b/packages/react-dom/npm/unstable-fizz.node.js
@@ -1,7 +1,7 @@
'use strict';
if (process.env.NODE_ENV === 'production') {
- module.exports = require('./cjs/react-dom-unstable-fizz.production.min.js');
+ module.exports = require('./cjs/react-dom-unstable-fizz.node.production.min.js');
} else {
- module.exports = require('./cjs/react-dom-unstable-fizz.development.js');
+ module.exports = require('./cjs/react-dom-unstable-fizz.node.development.js');
}
diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json
index c4d017e084a48..71192714262bc 100644
--- a/packages/react-dom/package.json
+++ b/packages/react-dom/package.json
@@ -31,13 +31,15 @@
"server.node.js",
"test-utils.js",
"unstable-fizz.js",
+ "unstable-fizz.browser.js",
"unstable-fizz.node.js",
"unstable-native-dependencies.js",
"cjs/",
"umd/"
],
"browser": {
- "./server.js": "./server.browser.js"
+ "./server.js": "./server.browser.js",
+ "./unstable-fizz.js": "./unstable-fizz.browser.js"
},
"browserify": {
"transform": [
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
new file mode 100644
index 0000000000000..3d34b661104bd
--- /dev/null
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+// Polyfills for test environment
+global.ReadableStream = require('@mattiasbuelens/web-streams-polyfill/ponyfill/es6').ReadableStream;
+global.TextEncoder = require('util').TextEncoder;
+
+let React;
+let ReactDOMFizzServer;
+
+describe('ReactDOMFizzServer', () => {
+ beforeEach(() => {
+ jest.resetModules();
+ React = require('react');
+ ReactDOMFizzServer = require('react-dom/unstable-fizz.browser');
+ });
+
+ async function readResult(stream) {
+ let reader = stream.getReader();
+ let result = '';
+ while (true) {
+ let {done, value} = await reader.read();
+ if (done) {
+ return result;
+ }
+ result += Buffer.from(value).toString('utf8');
+ }
+ }
+
+ it('should call renderToReadableStream', async () => {
+ let stream = ReactDOMFizzServer.renderToReadableStream(
+
hello world
,
+ );
+ let result = await readResult(stream);
+ expect(result).toBe('hello world
');
+ });
+});
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
similarity index 100%
rename from packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
rename to packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
diff --git a/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js b/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
new file mode 100644
index 0000000000000..17da2d7e48e87
--- /dev/null
+++ b/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
@@ -0,0 +1,34 @@
+/**
+ * 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 {
+ createRequest,
+ startWork,
+ startFlowing,
+} from 'react-stream/inline.dom-browser';
+
+function renderToReadableStream(children: ReactNodeList): ReadableStream {
+ let request;
+ return new ReadableStream({
+ start(controller) {
+ request = createRequest(children, controller);
+ startWork(request);
+ },
+ pull(controller) {
+ startFlowing(request, controller.desiredSize);
+ },
+ cancel(reason) {},
+ });
+}
+
+export default {
+ renderToReadableStream,
+};
diff --git a/packages/react-dom/src/server/ReactDOMFizzServerNode.js b/packages/react-dom/src/server/ReactDOMFizzServerNode.js
index 39947c4defc75..72b1bcb74272c 100644
--- a/packages/react-dom/src/server/ReactDOMFizzServerNode.js
+++ b/packages/react-dom/src/server/ReactDOMFizzServerNode.js
@@ -16,7 +16,10 @@ function createDrainHandler(destination, request) {
return () => startFlowing(request, 0);
}
-function pipeToNodeWritable(children: ReactNodeList, destination: Writable) {
+function pipeToNodeWritable(
+ children: ReactNodeList,
+ destination: Writable,
+): void {
let request = createRequest(children, destination);
destination.on('drain', createDrainHandler(destination, request));
startWork(request);
diff --git a/packages/react-dom/unstable-fizz.browser.js b/packages/react-dom/unstable-fizz.browser.js
new file mode 100644
index 0000000000000..4fb175ec6825e
--- /dev/null
+++ b/packages/react-dom/unstable-fizz.browser.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
+ */
+
+'use strict';
+
+const ReactDOMFizzServerBrowser = require('./src/server/ReactDOMFizzServerBrowser');
+
+// TODO: decide on the top-level export form.
+// This is hacky but makes it work with both Rollup and Jest
+module.exports = ReactDOMFizzServerBrowser.default || ReactDOMFizzServerBrowser;
diff --git a/packages/react-noop-renderer/src/ReactNoopServer.js b/packages/react-noop-renderer/src/ReactNoopServer.js
index 491675dc73d1c..2077687b9f9b1 100644
--- a/packages/react-noop-renderer/src/ReactNoopServer.js
+++ b/packages/react-noop-renderer/src/ReactNoopServer.js
@@ -27,6 +27,7 @@ const ReactNoopServer = ReactFizzStreamer({
destination.push(JSON.parse(Buffer.from((buffer: any)).toString('utf8')));
},
completeWriting(destination: Destination): void {},
+ close(destination: Destination): void {},
flushBuffered(destination: Destination): void {},
convertStringToBuffer(content: string): Uint8Array {
return Buffer.from(content, 'utf8');
diff --git a/packages/react-reconciler/inline.dom-browser.js b/packages/react-reconciler/inline.dom-browser.js
new file mode 100644
index 0000000000000..0d0c1546cc9a2
--- /dev/null
+++ b/packages/react-reconciler/inline.dom-browser.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.
+ */
+
+// This file intentionally does *not* have the Flow annotation.
+// Don't add it. See `./inline-typed.js` for an explanation.
+
+export * from './src/ReactFiberReconciler';
diff --git a/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-browser.js b/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-browser.js
new file mode 100644
index 0000000000000..d830c8501be27
--- /dev/null
+++ b/packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-browser.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-stream/inline.dom-browser.js b/packages/react-stream/inline.dom-browser.js
new file mode 100644
index 0000000000000..9bae815dca122
--- /dev/null
+++ b/packages/react-stream/inline.dom-browser.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.
+ */
+
+// This file intentionally does *not* have the Flow annotation.
+// Don't add it. See `./inline-typed.js` for an explanation.
+
+export * from './src/ReactFizzStreamer';
diff --git a/packages/react-stream/src/ReactFizzHostConfigBrowser.js b/packages/react-stream/src/ReactFizzHostConfigBrowser.js
new file mode 100644
index 0000000000000..390a6efc82749
--- /dev/null
+++ b/packages/react-stream/src/ReactFizzHostConfigBrowser.js
@@ -0,0 +1,37 @@
+/**
+ * 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 = ReadableStreamController;
+
+export function scheduleWork(callback: () => void) {
+ callback();
+}
+
+export function flushBuffered(destination: Destination) {
+ // WHATWG Streams do not yet have a way to flush the underlying
+ // transform streams. https://github.com/whatwg/streams/issues/960
+}
+
+export function beginWriting(destination: Destination) {}
+
+export function writeChunk(destination: Destination, buffer: Uint8Array) {
+ destination.enqueue(buffer);
+}
+
+export function completeWriting(destination: Destination) {}
+
+export function close(destination: Destination) {
+ destination.close();
+}
+
+const textEncoder = new TextEncoder();
+
+export function convertStringToBuffer(content: string): Uint8Array {
+ return textEncoder.encode(content);
+}
diff --git a/packages/react-stream/src/ReactFizzHostConfigNode.js b/packages/react-stream/src/ReactFizzHostConfigNode.js
index d6622376e3372..2ee9ddec354d9 100644
--- a/packages/react-stream/src/ReactFizzHostConfigNode.js
+++ b/packages/react-stream/src/ReactFizzHostConfigNode.js
@@ -39,6 +39,10 @@ export function completeWriting(destination: Destination) {
destination.uncork();
}
+export function close(destination: Destination) {
+ destination.end();
+}
+
export function convertStringToBuffer(content: string): Uint8Array {
return Buffer.from(content, 'utf8');
}
diff --git a/packages/react-stream/src/ReactFizzStreamer.js b/packages/react-stream/src/ReactFizzStreamer.js
index 6048073535623..80239287c2160 100644
--- a/packages/react-stream/src/ReactFizzStreamer.js
+++ b/packages/react-stream/src/ReactFizzStreamer.js
@@ -16,6 +16,7 @@ import {
writeChunk,
completeWriting,
flushBuffered,
+ close,
} from './ReactFizzHostConfig';
import {formatChunk} from './ReactFizzFormatConfig';
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
@@ -36,7 +37,8 @@ export function createRequest(
function performWork(request: OpaqueRequest): void {
let element = (request.children: any);
- if (element.$$typeof !== REACT_ELEMENT_TYPE) {
+ request.children = null;
+ if (element && element.$$typeof !== REACT_ELEMENT_TYPE) {
return;
}
let type = element.type;
@@ -55,6 +57,7 @@ function performWork(request: OpaqueRequest): void {
function flushCompletedChunks(request: OpaqueRequest) {
let destination = request.destination;
let chunks = request.completedChunks;
+ request.completedChunks = [];
beginWriting(destination);
try {
@@ -65,6 +68,7 @@ function flushCompletedChunks(request: OpaqueRequest) {
} finally {
completeWriting(destination);
}
+ close(destination);
}
export function startWork(request: OpaqueRequest): void {
diff --git a/packages/react-stream/src/forks/ReactFizzFormatConfig.dom-browser.js b/packages/react-stream/src/forks/ReactFizzFormatConfig.dom-browser.js
new file mode 100644
index 0000000000000..e3b8782adee7c
--- /dev/null
+++ b/packages/react-stream/src/forks/ReactFizzFormatConfig.dom-browser.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/ReactDOMFizzServerFormatConfig';
diff --git a/packages/react-stream/src/forks/ReactFizzHostConfig.custom.js b/packages/react-stream/src/forks/ReactFizzHostConfig.custom.js
index aca4559cd2334..71d876a10e5a1 100644
--- a/packages/react-stream/src/forks/ReactFizzHostConfig.custom.js
+++ b/packages/react-stream/src/forks/ReactFizzHostConfig.custom.js
@@ -31,4 +31,5 @@ export const beginWriting = $$$hostConfig.beginWriting;
export const writeChunk = $$$hostConfig.writeChunk;
export const completeWriting = $$$hostConfig.completeWriting;
export const flushBuffered = $$$hostConfig.flushBuffered;
+export const close = $$$hostConfig.close;
export const convertStringToBuffer = $$$hostConfig.convertStringToBuffer;
diff --git a/packages/react-stream/src/forks/ReactFizzHostConfig.dom-browser.js b/packages/react-stream/src/forks/ReactFizzHostConfig.dom-browser.js
new file mode 100644
index 0000000000000..ff949e1c746a1
--- /dev/null
+++ b/packages/react-stream/src/forks/ReactFizzHostConfig.dom-browser.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 '../ReactFizzHostConfigBrowser';
diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js
index 4932df206634f..f049b76f6b051 100644
--- a/scripts/rollup/bundles.js
+++ b/scripts/rollup/bundles.js
@@ -140,10 +140,17 @@ const bundles = [
},
/******* React DOM Fizz Server *******/
+ {
+ bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
+ moduleType: RENDERER,
+ entry: 'react-dom/unstable-fizz.browser',
+ global: 'ReactDOMFizzServer',
+ externals: ['react'],
+ },
{
bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
moduleType: RENDERER,
- entry: 'react-dom/unstable-fizz',
+ entry: 'react-dom/unstable-fizz.node',
global: 'ReactDOMFizzServer',
externals: ['react'],
},
diff --git a/scripts/rollup/results.json b/scripts/rollup/results.json
index b263a7dd2760e..91d4f827bac0d 100644
--- a/scripts/rollup/results.json
+++ b/scripts/rollup/results.json
@@ -942,57 +942,85 @@
"filename": "ReactDOMFizzServer-dev.js",
"bundleType": "FB_WWW_DEV",
"packageName": "react-dom",
- "size": 3660,
- "gzip": 1408
+ "size": 3772,
+ "gzip": 1432
},
{
"filename": "ReactDOMFizzServer-prod.js",
"bundleType": "FB_WWW_PROD",
"packageName": "react-dom",
- "size": 2092,
- "gzip": 844
+ "size": 2211,
+ "gzip": 874
},
{
"filename": "react-noop-renderer-server.development.js",
"bundleType": "NODE_DEV",
"packageName": "react-noop-renderer",
- "size": 1825,
- "gzip": 864
+ "size": 1861,
+ "gzip": 869
},
{
"filename": "react-noop-renderer-server.production.min.js",
"bundleType": "NODE_PROD",
"packageName": "react-noop-renderer",
- "size": 785,
- "gzip": 477
+ "size": 804,
+ "gzip": 482
},
{
"filename": "react-stream.development.js",
"bundleType": "NODE_DEV",
"packageName": "react-stream",
- "size": 4508,
- "gzip": 1650
+ "size": 4633,
+ "gzip": 1683
},
{
"filename": "react-stream.production.min.js",
"bundleType": "NODE_PROD",
"packageName": "react-stream",
- "size": 1161,
- "gzip": 631
+ "size": 1224,
+ "gzip": 655
},
{
- "filename": "react-dom-unstable-fizz.development.js",
+ "filename": "react-dom-unstable-fizz.browser.development.js",
+ "bundleType": "UMD_DEV",
+ "packageName": "react-dom",
+ "size": 3704,
+ "gzip": 1463
+ },
+ {
+ "filename": "react-dom-unstable-fizz.browser.production.min.js",
+ "bundleType": "UMD_PROD",
+ "packageName": "react-dom",
+ "size": 1227,
+ "gzip": 697
+ },
+ {
+ "filename": "react-dom-unstable-fizz.browser.development.js",
+ "bundleType": "NODE_DEV",
+ "packageName": "react-dom",
+ "size": 3528,
+ "gzip": 1416
+ },
+ {
+ "filename": "react-dom-unstable-fizz.browser.production.min.js",
+ "bundleType": "NODE_PROD",
+ "packageName": "react-dom",
+ "size": 1063,
+ "gzip": 628
+ },
+ {
+ "filename": "react-dom-unstable-fizz.node.development.js",
"bundleType": "NODE_DEV",
"packageName": "react-dom",
- "size": 3663,
- "gzip": 1417
+ "size": 3780,
+ "gzip": 1443
},
{
- "filename": "react-dom-unstable-fizz.production.min.js",
+ "filename": "react-dom-unstable-fizz.node.production.min.js",
"bundleType": "NODE_PROD",
"packageName": "react-dom",
- "size": 1073,
- "gzip": 636
+ "size": 1122,
+ "gzip": 659
}
]
}
\ No newline at end of file
diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js
index 137332f990c6f..1f66699387638 100644
--- a/scripts/shared/inlinedHostConfigs.js
+++ b/scripts/shared/inlinedHostConfigs.js
@@ -9,7 +9,13 @@
module.exports = [
{
shortName: 'dom',
- entryPoints: ['react-dom', 'react-dom/unstable-fizz'],
+ entryPoints: ['react-dom', 'react-dom/unstable-fizz.node'],
+ isFlowTyped: true,
+ isFizzSupported: true,
+ },
+ {
+ shortName: 'dom-browser',
+ entryPoints: ['react-dom/unstable-fizz.browser'],
isFlowTyped: true,
isFizzSupported: true,
},
diff --git a/yarn.lock b/yarn.lock
index c9ffffa9fd9c8..5bb72e40fd3aa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -94,6 +94,18 @@
lodash "^4.17.10"
to-fast-properties "^2.0.0"
+"@mattiasbuelens/web-streams-polyfill@0.1.0":
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/@mattiasbuelens/web-streams-polyfill/-/web-streams-polyfill-0.1.0.tgz#c06ebfa7e00cc512a878c3aaae4cf113ac89ac24"
+ integrity sha512-oMsvblvOezdM/j1ph0uU8s6Wm0EfCyMZtZcxQ232CqSpjm08lrKPizeMltN0eVv4dQf0DDFaxUFyiz8x51lgAA==
+ dependencies:
+ "@types/whatwg-streams" "^0.0.6"
+
+"@types/whatwg-streams@^0.0.6":
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/@types/whatwg-streams/-/whatwg-streams-0.0.6.tgz#5062c67efb695c886fe3dbb9618df35aac418503"
+ integrity sha512-O4Hat94N1RUCObqAbVUtd6EcucseqBcpfbFXzy12CYF6BQVHWR+ztDA3YPjewCmdKHYZ5VA7TZ5hq2bMyqxiBw==
+
abab@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"