@samitouri / QOS-React / commits / 1d25aa5787

[Fizz] New Server Rendering Infra (#14144)

* [Fizz] Add Flow/Jest/Rollup build infra Add a new package for react-stream which allows for custom server renderer outputs. I picked the name because it's a reasonable name but also because the npm name is currently owned by a friend of the project. The react-dom build has its own inlined server renderer under the name `react-dom/fizz`. There is also a noop renderer to be used for testing. At some point we might add a public one to test-renderer but for now I don't want to have to think about public API design for the tests. * Add FormatConfig too We need to separate the format (DOM, React Native, etc) from the host running the server (Node, Browser, etc). * Basic wiring between Node, Noop and DOM configs The Node DOM API is pipeToNodeStream which accepts a writable stream. * Merge host and format config in dynamic react-stream entry point Simpler API this way but also avoids having to fork the wrapper config. Fixes noop builds. * Add setImmediate/Buffer globals to lint config Used by the server renderer * Properly include fizz.node.js Also use forwarding to it from fizz.js in builds so that tests covers this. * Make react-stream private since we're not ready to publish or even name it yet * Rename Renderer -> Streamer * Prefix react-dom/fizz with react-dom/unstable-fizz * Add Fizz Browser host config This lets Fizz render to WHATWG streams. E.g. for rendering in a Service Worker. I added react-dom/unstable-fizz.browser as the entry point for this. Since we now have two configurations of DOM. I had to add another inlinedHostConfigs configuration called `dom-browser`. The reconciler treats this configuration the same as `dom`. For stream it checks against the ReactFizzHostConfigBrowser instead of the Node one. * Add Fizz Browser Fixture This is for testing server rendering - on the client. * Lower version number to detach it from react-reconciler version

Sebastian Markbåge committed Nov 30, 2018 at 11:38 UTC 1d25aa5787d4e19704c049c3cfa985d3b5190e0d
48 files changed +1214 -87
fixtures/fizz-ssr-browser/index.html new
+40
@@ -0,0 +1,40 @@
1 +<!DOCTYPE html>
2 +<html style="width: 100%; height: 100%; overflow: hidden">
3 + <head>
4 + <meta charset="utf-8">
5 + <title>Fizz Example</title>
6 + </head>
7 + <body>
8 + <h1>Fizz Example</h1>
9 + <div id="container">
10 + <p>
11 + To install React, follow the instructions on
12 + <a href="https://github.com/facebook/react/">GitHub</a>.
13 + </p>
14 + <p>
15 + If you can see this, React is <strong>not</strong> working right.
16 + If you checked out the source from GitHub make sure to run <code>npm run build</code>.
17 + </p>
18 + </div>
19 + <script src="../../build/dist/react.development.js"></script>
20 + <script src="../../build/dist/react-dom-unstable-fizz.browser.development.js"></script>
21 + <script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
22 + <script type="text/babel">
23 + let stream = ReactDOMFizzServer.renderToReadableStream(<body>Success</body>);
24 + let response = new Response(stream, {
25 + headers: {'Content-Type': 'text/html'},
26 + });
27 + display(response);
28 +
29 + async function display(responseToDisplay) {
30 + let blob = await responseToDisplay.blob();
31 + let url = URL.createObjectURL(blob);
32 + let iframe = document.createElement('iframe');
33 + iframe.src = url;
34 + let container = document.getElementById('container');
35 + container.innerHTML = '';
36 + container.appendChild(iframe);
37 + }
38 + </script>
39 + </body>
40 +</html>
package.json
+2 -1
@@ -84,7 +84,8 @@
84 "targz": "^1.0.1",
85 "through2": "^2.0.0",
86 "tmp": "~0.0.28",
87 - "typescript": "~1.8.10"
87 + "typescript": "~1.8.10",
88 + "@mattiasbuelens/web-streams-polyfill": "0.1.0"
89 },
90 "devEngines": {
91 "node": "8.x || 9.x || 10.x"
packages/react-dom/npm/unstable-fizz.browser.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-dom-unstable-fizz.browser.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-dom-unstable-fizz.browser.development.js');
7 +}
packages/react-dom/npm/unstable-fizz.js new
+3
@@ -0,0 +1,3 @@
1 +'use strict';
2 +
3 +module.exports = require('./unstable-fizz.node');
packages/react-dom/npm/unstable-fizz.node.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-dom-unstable-fizz.node.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-dom-unstable-fizz.node.development.js');
7 +}
packages/react-dom/package.json
+5 -1
@@ -32,12 +32,16 @@
32 "server.node.js",
33 "test-utils.js",
34 "unstable-fire.js",
35 + "unstable-fizz.js",
36 + "unstable-fizz.browser.js",
37 + "unstable-fizz.node.js",
38 "unstable-native-dependencies.js",
39 "cjs/",
40 "umd/"
41 ],
42 "browser": {
40 - "./server.js": "./server.browser.js"
43 + "./server.js": "./server.browser.js",
44 + "./unstable-fizz.js": "./unstable-fizz.browser.js"
45 },
46 "browserify": {
47 "transform": [
packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js new
+45
@@ -0,0 +1,45 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @emails react-core
8 + */
9 +
10 +'use strict';
11 +
12 +// Polyfills for test environment
13 +global.ReadableStream = require('@mattiasbuelens/web-streams-polyfill/ponyfill/es6').ReadableStream;
14 +global.TextEncoder = require('util').TextEncoder;
15 +
16 +let React;
17 +let ReactDOMFizzServer;
18 +
19 +describe('ReactDOMFizzServer', () => {
20 + beforeEach(() => {
21 + jest.resetModules();
22 + React = require('react');
23 + ReactDOMFizzServer = require('react-dom/unstable-fizz.browser');
24 + });
25 +
26 + async function readResult(stream) {
27 + let reader = stream.getReader();
28 + let result = '';
29 + while (true) {
30 + let {done, value} = await reader.read();
31 + if (done) {
32 + return result;
33 + }
34 + result += Buffer.from(value).toString('utf8');
35 + }
36 + }
37 +
38 + it('should call renderToReadableStream', async () => {
39 + let stream = ReactDOMFizzServer.renderToReadableStream(
40 + <div>hello world</div>,
41 + );
42 + let result = await readResult(stream);
43 + expect(result).toBe('<div>hello world</div>');
44 + });
45 +});
packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js new
+39
@@ -0,0 +1,39 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @emails react-core
8 + * @jest-environment node
9 + */
10 +
11 +'use strict';
12 +
13 +let Stream;
14 +let React;
15 +let ReactDOMFizzServer;
16 +
17 +describe('ReactDOMFizzServer', () => {
18 + beforeEach(() => {
19 + jest.resetModules();
20 + React = require('react');
21 + ReactDOMFizzServer = require('react-dom/unstable-fizz');
22 + Stream = require('stream');
23 + });
24 +
25 + function getTestWritable() {
26 + let writable = new Stream.PassThrough();
27 + writable.setEncoding('utf8');
28 + writable.result = '';
29 + writable.on('data', chunk => (writable.result += chunk));
30 + return writable;
31 + }
32 +
33 + it('should call pipeToNodeWritable', () => {
34 + let writable = getTestWritable();
35 + ReactDOMFizzServer.pipeToNodeWritable(<div>hello world</div>, writable);
36 + jest.runAllTimers();
37 + expect(writable.result).toBe('<div>hello world</div>');
38 + });
39 +});
packages/react-dom/src/server/ReactDOMFizzServerBrowser.js new
+34
@@ -0,0 +1,34 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {ReactNodeList} from 'shared/ReactTypes';
11 +
12 +import {
13 + createRequest,
14 + startWork,
15 + startFlowing,
16 +} from 'react-stream/inline.dom-browser';
17 +
18 +function renderToReadableStream(children: ReactNodeList): ReadableStream {
19 + let request;
20 + return new ReadableStream({
21 + start(controller) {
22 + request = createRequest(children, controller);
23 + startWork(request);
24 + },
25 + pull(controller) {
26 + startFlowing(request, controller.desiredSize);
27 + },
28 + cancel(reason) {},
29 + });
30 +}
31 +
32 +export default {
33 + renderToReadableStream,
34 +};
packages/react-dom/src/server/ReactDOMFizzServerFormatConfig.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import {convertStringToBuffer} from 'react-stream/src/ReactFizzHostConfig';
11 +
12 +export function formatChunk(type: string, props: Object): Uint8Array {
13 + let str = '<' + type + '>';
14 + if (typeof props.children === 'string') {
15 + str += props.children;
16 + }
17 + str += '</' + type + '>';
18 + return convertStringToBuffer(str);
19 +}
packages/react-dom/src/server/ReactDOMFizzServerNode.js new
+30
@@ -0,0 +1,30 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {ReactNodeList} from 'shared/ReactTypes';
11 +import type {Writable} from 'stream';
12 +
13 +import {createRequest, startWork, startFlowing} from 'react-stream/inline.dom';
14 +
15 +function createDrainHandler(destination, request) {
16 + return () => startFlowing(request, 0);
17 +}
18 +
19 +function pipeToNodeWritable(
20 + children: ReactNodeList,
21 + destination: Writable,
22 +): void {
23 + let request = createRequest(children, destination);
24 + destination.on('drain', createDrainHandler(destination, request));
25 + startWork(request);
26 +}
27 +
28 +export default {
29 + pipeToNodeWritable,
30 +};
packages/react-dom/unstable-fizz.browser.js new
+16
@@ -0,0 +1,16 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +const ReactDOMFizzServerBrowser = require('./src/server/ReactDOMFizzServerBrowser');
13 +
14 +// TODO: decide on the top-level export form.
15 +// This is hacky but makes it work with both Rollup and Jest
16 +module.exports = ReactDOMFizzServerBrowser.default || ReactDOMFizzServerBrowser;
packages/react-dom/unstable-fizz.js new
+12
@@ -0,0 +1,12 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +module.exports = require('./unstable-fizz.node');
packages/react-dom/unstable-fizz.node.js new
+16
@@ -0,0 +1,16 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +const ReactDOMFizzServerNode = require('./src/server/ReactDOMFizzServerNode');
13 +
14 +// TODO: decide on the top-level export form.
15 +// This is hacky but makes it work with both Rollup and Jest
16 +module.exports = ReactDOMFizzServerNode.default || ReactDOMFizzServerNode;
packages/react-noop-renderer/npm/server.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-noop-renderer-server.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-noop-renderer-server.development.js');
7 +}
packages/react-noop-renderer/package.json
+3 -1
@@ -10,7 +10,8 @@
10 "object-assign": "^4.1.1",
11 "prop-types": "^15.6.2",
12 "regenerator-runtime": "^0.11.0",
13 - "react-reconciler": "*"
13 + "react-reconciler": "*",
14 + "react-stream": "*"
15 },
16 "peerDependencies": {
17 "react": "^16.0.0"
@@ -21,6 +22,7 @@
22 "build-info.json",
23 "index.js",
24 "persistent.js",
25 + "server.js",
26 "cjs/"
27 ]
28 }
packages/react-noop-renderer/server.js new
+16
@@ -0,0 +1,16 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +'use strict';
11 +
12 +const ReactNoopServer = require('./src/ReactNoopServer');
13 +
14 +// TODO: decide on the top-level export form.
15 +// This is hacky but makes it work with both Rollup and Jest.
16 +module.exports = ReactNoopServer.default || ReactNoopServer;
packages/react-noop-renderer/src/ReactNoopServer.js new
+49
@@ -0,0 +1,49 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +/**
11 + * This is a renderer of React that doesn't have a render target output.
12 + * It is useful to demonstrate the internals of the reconciler in isolation
13 + * and for testing semantics of reconciliation separate from the host
14 + * environment.
15 + */
16 +
17 +import ReactFizzStreamer from 'react-stream';
18 +
19 +type Destination = Array<string>;
20 +
21 +const ReactNoopServer = ReactFizzStreamer({
22 + scheduleWork(callback: () => void) {
23 + callback();
24 + },
25 + beginWriting(destination: Destination): void {},
26 + writeChunk(destination: Destination, buffer: Uint8Array): void {
27 + destination.push(JSON.parse(Buffer.from((buffer: any)).toString('utf8')));
28 + },
29 + completeWriting(destination: Destination): void {},
30 + close(destination: Destination): void {},
31 + flushBuffered(destination: Destination): void {},
32 + convertStringToBuffer(content: string): Uint8Array {
33 + return Buffer.from(content, 'utf8');
34 + },
35 + formatChunk(type: string, props: Object): Uint8Array {
36 + return Buffer.from(JSON.stringify({type, props}), 'utf8');
37 + },
38 +});
39 +
40 +function render(children: React$Element<any>): Destination {
41 + let destination: Destination = [];
42 + let request = ReactNoopServer.createRequest(children, destination);
43 + ReactNoopServer.startWork(request);
44 + return destination;
45 +}
46 +
47 +export default {
48 + render,
49 +};
packages/react-reconciler/inline.dom-browser.js new
+11
@@ -0,0 +1,11 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +// This file intentionally does *not* have the Flow annotation.
9 +// Don't add it. See `./inline-typed.js` for an explanation.
10 +
11 +export * from './src/ReactFiberReconciler';
packages/react-reconciler/src/forks/ReactFiberHostConfig.dom-browser.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from 'react-dom/src/client/ReactDOMHostConfig';
packages/react-stream/README.md new
+25
@@ -0,0 +1,25 @@
1 +# react-stream
2 +
3 +This is an experimental package for creating custom React streaming server renderers.
4 +
5 +**Its API is not as stable as that of React, React Native, or React DOM, and does not follow the common versioning scheme.**
6 +
7 +**Use it at your own risk.**
8 +
9 +## API
10 +
11 +```js
12 +var Renderer = require('react-stream');
13 +
14 +var HostConfig = {
15 + // You'll need to implement some methods here.
16 + // See below for more information and examples.
17 +};
18 +
19 +var MyRenderer = Renderer(HostConfig);
20 +
21 +var RendererPublicAPI = {
22 +};
23 +
24 +module.exports = RendererPublicAPI;
25 +```
packages/react-stream/index.js new
+26
@@ -0,0 +1,26 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +// This entry point is intentionally not typed. It exists only for third-party
9 +// renderers. The renderers we ship (such as React DOM) instead import a named
10 +// "inline" entry point (for example, `react-stream/inline.dom`). It uses
11 +// the same code, but the Flow configuration redirects the host config to its
12 +// real implementation so we can check it against exact intended host types.
13 +//
14 +// Only one renderer (the one you passed to `yarn flow <renderer>`) is fully
15 +// type-checked at any given time. The Flow config maps the
16 +// `react-stream/inline.<renderer>` import (which is *not* Flow typed) to
17 +// `react-stream/inline-typed` (which *is*) for the current renderer.
18 +// On CI, we run Flow checks for each renderer separately.
19 +
20 +'use strict';
21 +
22 +const ReactFizzStreamer = require('./src/ReactFizzStreamer');
23 +
24 +// TODO: decide on the top-level export form.
25 +// This is hacky but makes it work with both Rollup and Jest.
26 +module.exports = ReactFizzStreamer.default || ReactFizzStreamer;
packages/react-stream/inline-typed.js new
+24
@@ -0,0 +1,24 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +// This file must have the Flow annotation.
11 +//
12 +// This is the Flow-typed entry point for the renderer. It should not be
13 +// imported directly in code. Instead, our Flow configuration uses this entry
14 +// point for the currently checked renderer (the one you passed to `yarn flow`).
15 +//
16 +// For example, if you run `yarn flow dom`, `react-stream/inline.dom` points
17 +// to this module (and thus will be considered Flow-typed). But other renderers
18 +// (e.g. `react-test-renderer`) will see stream as untyped during the check.
19 +//
20 +// We can't make all entry points typed at the same time because different
21 +// renderers have different host config types. So we check them one by one.
22 +// We run Flow on all renderers on CI.
23 +
24 +export * from './src/ReactFizzStreamer';
packages/react-stream/inline.dom-browser.js new
+11
@@ -0,0 +1,11 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +// This file intentionally does *not* have the Flow annotation.
9 +// Don't add it. See `./inline-typed.js` for an explanation.
10 +
11 +export * from './src/ReactFizzStreamer';
packages/react-stream/inline.dom.js new
+11
@@ -0,0 +1,11 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +// This file intentionally does *not* have the Flow annotation.
9 +// Don't add it. See `./inline-typed.js` for an explanation.
10 +
11 +export * from './src/ReactFizzStreamer';
packages/react-stream/npm/index.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-stream.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-stream.development.js');
7 +}
packages/react-stream/package.json new
+36
@@ -0,0 +1,36 @@
1 +{
2 + "name": "react-stream",
3 + "description": "React package for creating custom streaming server renderers.",
4 + "version": "0.1.0",
5 + "private": true,
6 + "keywords": [
7 + "react"
8 + ],
9 + "homepage": "https://reactjs.org/",
10 + "bugs": "https://github.com/facebook/react/issues",
11 + "license": "MIT",
12 + "files": [
13 + "LICENSE",
14 + "README.md",
15 + "index.js",
16 + "cjs/"
17 + ],
18 + "main": "index.js",
19 + "repository": "facebook/react",
20 + "engines": {
21 + "node": ">=0.10.0"
22 + },
23 + "peerDependencies": {
24 + "react": "^16.0.0"
25 + },
26 + "dependencies": {
27 + "loose-envify": "^1.1.0",
28 + "object-assign": "^4.1.1",
29 + "prop-types": "^15.6.2"
30 + },
31 + "browserify": {
32 + "transform": [
33 + "loose-envify"
34 + ]
35 + }
36 +}
packages/react-stream/src/ReactFizzFormatConfig.js new
+20
@@ -0,0 +1,20 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import invariant from 'shared/invariant';
11 +
12 +// We expect that our Rollup, Jest, and Flow configurations
13 +// always shim this module with the corresponding host config
14 +// (either provided by a renderer, or a generic shim for npm).
15 +//
16 +// We should never resolve to this file, but it exists to make
17 +// sure that if we *do* accidentally break the configuration,
18 +// the failure isn't silent.
19 +
20 +invariant(false, 'This module must be shimmed by a specific renderer.');
packages/react-stream/src/ReactFizzHostConfig.js new
+20
@@ -0,0 +1,20 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import invariant from 'shared/invariant';
11 +
12 +// We expect that our Rollup, Jest, and Flow configurations
13 +// always shim this module with the corresponding host config
14 +// (either provided by a renderer, or a generic shim for npm).
15 +//
16 +// We should never resolve to this file, but it exists to make
17 +// sure that if we *do* accidentally break the configuration,
18 +// the failure isn't silent.
19 +
20 +invariant(false, 'This module must be shimmed by a specific renderer.');
packages/react-stream/src/ReactFizzHostConfigBrowser.js new
+37
@@ -0,0 +1,37 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export type Destination = ReadableStreamController;
11 +
12 +export function scheduleWork(callback: () => void) {
13 + callback();
14 +}
15 +
16 +export function flushBuffered(destination: Destination) {
17 + // WHATWG Streams do not yet have a way to flush the underlying
18 + // transform streams. https://github.com/whatwg/streams/issues/960
19 +}
20 +
21 +export function beginWriting(destination: Destination) {}
22 +
23 +export function writeChunk(destination: Destination, buffer: Uint8Array) {
24 + destination.enqueue(buffer);
25 +}
26 +
27 +export function completeWriting(destination: Destination) {}
28 +
29 +export function close(destination: Destination) {
30 + destination.close();
31 +}
32 +
33 +const textEncoder = new TextEncoder();
34 +
35 +export function convertStringToBuffer(content: string): Uint8Array {
36 + return textEncoder.encode(content);
37 +}
packages/react-stream/src/ReactFizzHostConfigNode.js new
+48
@@ -0,0 +1,48 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Writable} from 'stream';
11 +
12 +type MightBeFlushable = {flush?: () => void};
13 +
14 +export type Destination = Writable & MightBeFlushable;
15 +
16 +export function scheduleWork(callback: () => void) {
17 + setImmediate(callback);
18 +}
19 +
20 +export function flushBuffered(destination: Destination) {
21 + // If we don't have any more data to send right now.
22 + // Flush whatever is in the buffer to the wire.
23 + if (typeof destination.flush === 'function') {
24 + // By convention the Zlib streams provide a flush function for this purpose.
25 + destination.flush();
26 + }
27 +}
28 +
29 +export function beginWriting(destination: Destination) {
30 + destination.cork();
31 +}
32 +
33 +export function writeChunk(destination: Destination, buffer: Uint8Array) {
34 + let nodeBuffer = ((buffer: any): Buffer); // close enough
35 + destination.write(nodeBuffer);
36 +}
37 +
38 +export function completeWriting(destination: Destination) {
39 + destination.uncork();
40 +}
41 +
42 +export function close(destination: Destination) {
43 + destination.end();
44 +}
45 +
46 +export function convertStringToBuffer(content: string): Uint8Array {
47 + return Buffer.from(content, 'utf8');
48 +}
packages/react-stream/src/ReactFizzStreamer.js new
+85
@@ -0,0 +1,85 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {Destination} from './ReactFizzHostConfig';
11 +import type {ReactNodeList} from 'shared/ReactTypes';
12 +
13 +import {
14 + scheduleWork,
15 + beginWriting,
16 + writeChunk,
17 + completeWriting,
18 + flushBuffered,
19 + close,
20 +} from './ReactFizzHostConfig';
21 +import {formatChunk} from './ReactFizzFormatConfig';
22 +import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
23 +
24 +type OpaqueRequest = {
25 + destination: Destination,
26 + children: ReactNodeList,
27 + completedChunks: Array<Uint8Array>,
28 + flowing: boolean,
29 +};
30 +
31 +export function createRequest(
32 + children: ReactNodeList,
33 + destination: Destination,
34 +): OpaqueRequest {
35 + return {destination, children, completedChunks: [], flowing: false};
36 +}
37 +
38 +function performWork(request: OpaqueRequest): void {
39 + let element = (request.children: any);
40 + request.children = null;
41 + if (element && element.$$typeof !== REACT_ELEMENT_TYPE) {
42 + return;
43 + }
44 + let type = element.type;
45 + let props = element.props;
46 + if (typeof type !== 'string') {
47 + return;
48 + }
49 + request.completedChunks.push(formatChunk(type, props));
50 + if (request.flowing) {
51 + flushCompletedChunks(request);
52 + }
53 +
54 + flushBuffered(request.destination);
55 +}
56 +
57 +function flushCompletedChunks(request: OpaqueRequest) {
58 + let destination = request.destination;
59 + let chunks = request.completedChunks;
60 + request.completedChunks = [];
61 +
62 + beginWriting(destination);
63 + try {
64 + for (let i = 0; i < chunks.length; i++) {
65 + let chunk = chunks[i];
66 + writeChunk(destination, chunk);
67 + }
68 + } finally {
69 + completeWriting(destination);
70 + }
71 + close(destination);
72 +}
73 +
74 +export function startWork(request: OpaqueRequest): void {
75 + request.flowing = true;
76 + scheduleWork(() => performWork(request));
77 +}
78 +
79 +export function startFlowing(
80 + request: OpaqueRequest,
81 + desiredBytes: number,
82 +): void {
83 + request.flowing = false;
84 + flushCompletedChunks(request);
85 +}
packages/react-stream/src/__tests__/ReactServer-test.js new
+28
@@ -0,0 +1,28 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @emails react-core
8 + * @jest-environment node
9 + */
10 +
11 +'use strict';
12 +
13 +let React;
14 +let ReactNoopServer;
15 +
16 +describe('ReactServer', () => {
17 + beforeEach(() => {
18 + jest.resetModules();
19 +
20 + React = require('react');
21 + ReactNoopServer = require('react-noop-renderer/server');
22 + });
23 +
24 + it('can call render', () => {
25 + let result = ReactNoopServer.render(<div>hello world</div>);
26 + expect(result).toEqual([{type: 'div', props: {children: 'hello world'}}]);
27 + });
28 +});
packages/react-stream/src/forks/ReactFizzFormatConfig.custom.js new
+29
@@ -0,0 +1,29 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +// This is a host config that's used for the `react-stream` package on npm.
11 +// It is only used by third-party renderers.
12 +//
13 +// Its API lets you pass the host config as an argument.
14 +// However, inside the `react-stream` we treat host config as a module.
15 +// This file is a shim between two worlds.
16 +//
17 +// It works because the `react-stream` bundle is wrapped in something like:
18 +//
19 +// module.exports = function ($$$config) {
20 +// /* renderer code */
21 +// }
22 +//
23 +// So `$$$config` looks like a global variable, but it's
24 +// really an argument to a top-level wrapping function.
25 +
26 +declare var $$$hostConfig: any;
27 +export opaque type Destination = mixed; // eslint-disable-line no-undef
28 +
29 +export const formatChunk = $$$hostConfig.formatChunk;
packages/react-stream/src/forks/ReactFizzFormatConfig.dom-browser.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from 'react-dom/src/server/ReactDOMFizzServerFormatConfig';
packages/react-stream/src/forks/ReactFizzFormatConfig.dom.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from 'react-dom/src/server/ReactDOMFizzServerFormatConfig';
packages/react-stream/src/forks/ReactFizzHostConfig.custom.js new
+35
@@ -0,0 +1,35 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +// This is a host config that's used for the `react-stream` package on npm.
11 +// It is only used by third-party renderers.
12 +//
13 +// Its API lets you pass the host config as an argument.
14 +// However, inside the `react-stream` we treat host config as a module.
15 +// This file is a shim between two worlds.
16 +//
17 +// It works because the `react-stream` bundle is wrapped in something like:
18 +//
19 +// module.exports = function ($$$config) {
20 +// /* renderer code */
21 +// }
22 +//
23 +// So `$$$config` looks like a global variable, but it's
24 +// really an argument to a top-level wrapping function.
25 +
26 +declare var $$$hostConfig: any;
27 +export opaque type Destination = mixed; // eslint-disable-line no-undef
28 +
29 +export const scheduleWork = $$$hostConfig.scheduleWork;
30 +export const beginWriting = $$$hostConfig.beginWriting;
31 +export const writeChunk = $$$hostConfig.writeChunk;
32 +export const completeWriting = $$$hostConfig.completeWriting;
33 +export const flushBuffered = $$$hostConfig.flushBuffered;
34 +export const close = $$$hostConfig.close;
35 +export const convertStringToBuffer = $$$hostConfig.convertStringToBuffer;
packages/react-stream/src/forks/ReactFizzHostConfig.dom-browser.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from '../ReactFizzHostConfigBrowser';
packages/react-stream/src/forks/ReactFizzHostConfig.dom.js new
+10
@@ -0,0 +1,10 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +export * from '../ReactFizzHostConfigNode';
scripts/flow/createFlowConfigs.js
+6 -2
@@ -18,15 +18,19 @@ const configTemplate = fs
18 .readFileSync(__dirname + '/config/flowconfig')
19 .toString();
20
21 -function writeConfig(renderer) {
21 +function writeConfig(renderer, isFizzSupported) {
22 const folder = __dirname + '/' + renderer;
23 mkdirp.sync(folder);
24
25 + const fizzRenderer = isFizzSupported ? renderer : 'custom';
26 const config = configTemplate.replace(
27 '%REACT_RENDERER_FLOW_OPTIONS%',
28 `
29 module.name_mapper='react-reconciler/inline.${renderer}$$' -> 'react-reconciler/inline-typed'
30 module.name_mapper='ReactFiberHostConfig$$' -> 'forks/ReactFiberHostConfig.${renderer}'
31 +module.name_mapper='react-stream/inline.${renderer}$$' -> 'react-stream/inline-typed'
32 +module.name_mapper='ReactFizzHostConfig$$' -> 'forks/ReactFizzHostConfig.${fizzRenderer}'
33 +module.name_mapper='ReactFizzFormatConfig$$' -> 'forks/ReactFizzFormatConfig.${fizzRenderer}'
34 `.trim(),
35 );
36
@@ -61,6 +65,6 @@ ${disclaimer}
65 // so that we can run those checks in parallel if we want.
66 inlinedHostConfigs.forEach(rendererInfo => {
67 if (rendererInfo.isFlowTyped) {
64 - writeConfig(rendererInfo.shortName);
68 + writeConfig(rendererInfo.shortName, rendererInfo.isFizzSupported);
69 }
70 });
scripts/jest/setupHostConfigs.js
+49
@@ -17,6 +17,15 @@ jest.mock('react-reconciler/persistent', () => {
17 return require.requireActual('react-reconciler/persistent');
18 };
19 });
20 +const shimFizzHostConfigPath = 'react-stream/src/ReactFizzHostConfig';
21 +const shimFizzFormatConfigPath = 'react-stream/src/ReactFizzFormatConfig';
22 +jest.mock('react-stream', () => {
23 + return config => {
24 + jest.mock(shimFizzHostConfigPath, () => config);
25 + jest.mock(shimFizzFormatConfigPath, () => config);
26 + return require.requireActual('react-stream');
27 + };
28 +});
29
30 // But for inlined host configs (such as React DOM, Native, etc), we
31 // mock their named entry points to establish a host config mapping.
@@ -55,6 +64,46 @@ inlinedHostConfigs.forEach(rendererInfo => {
64
65 return renderer;
66 });
67 +
68 + if (rendererInfo.isFizzSupported) {
69 + jest.mock(`react-stream/inline.${rendererInfo.shortName}`, () => {
70 + let hasImportedShimmedConfig = false;
71 +
72 + // We want the renderer to pick up the host config for this renderer.
73 + jest.mock(shimFizzHostConfigPath, () => {
74 + hasImportedShimmedConfig = true;
75 + return require.requireActual(
76 + `react-stream/src/forks/ReactFizzHostConfig.${
77 + rendererInfo.shortName
78 + }.js`
79 + );
80 + });
81 + jest.mock(shimFizzFormatConfigPath, () => {
82 + hasImportedShimmedConfig = true;
83 + return require.requireActual(
84 + `react-stream/src/forks/ReactFizzFormatConfig.${
85 + rendererInfo.shortName
86 + }.js`
87 + );
88 + });
89 +
90 + const renderer = require.requireActual('react-stream');
91 + // If the shimmed config factory function above has not run,
92 + // it means this test file loads more than one renderer
93 + // but doesn't reset modules between them. This won't work.
94 + if (!hasImportedShimmedConfig) {
95 + throw new Error(
96 + `Could not import the "${rendererInfo.shortName}" renderer ` +
97 + `in this suite because another renderer has already been ` +
98 + `loaded earlier. Call jest.resetModules() before importing any ` +
99 + `of the following entry points:\n\n` +
100 + rendererInfo.entryPoints.map(entry => ` * ${entry}`)
101 + );
102 + }
103 +
104 + return renderer;
105 + });
106 + }
107 });
108
109 // Make it possible to import this module inside
scripts/rollup/bundles.js
+47
@@ -158,6 +158,22 @@ const bundles = [
158 externals: ['react', 'stream'],
159 },
160
161 + /******* React DOM Fizz Server *******/
162 + {
163 + bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
164 + moduleType: RENDERER,
165 + entry: 'react-dom/unstable-fizz.browser',
166 + global: 'ReactDOMFizzServer',
167 + externals: ['react'],
168 + },
169 + {
170 + bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
171 + moduleType: RENDERER,
172 + entry: 'react-dom/unstable-fizz.node',
173 + global: 'ReactDOMFizzServer',
174 + externals: ['react'],
175 + },
176 +
177 /******* React ART *******/
178 {
179 bundleTypes: [
@@ -320,6 +336,28 @@ const bundles = [
336 }),
337 },
338
339 + /******* React Noop Server Renderer (used for tests) *******/
340 + {
341 + bundleTypes: [NODE_DEV, NODE_PROD],
342 + moduleType: RENDERER,
343 + entry: 'react-noop-renderer/server',
344 + global: 'ReactNoopRendererServer',
345 + externals: ['react', 'expect'],
346 + // React Noop uses generators. However GCC currently
347 + // breaks when we attempt to use them in the output.
348 + // So we precompile them with regenerator, and include
349 + // it as a runtime dependency of React Noop. In practice
350 + // this isn't an issue because React Noop is only used
351 + // in our tests. We wouldn't want to do this for any
352 + // public package though.
353 + babel: opts =>
354 + Object.assign({}, opts, {
355 + plugins: opts.plugins.concat([
356 + require.resolve('babel-plugin-transform-regenerator'),
357 + ]),
358 + }),
359 + },
360 +
361 /******* React Reconciler *******/
362 {
363 bundleTypes: [NODE_DEV, NODE_PROD],
@@ -338,6 +376,15 @@ const bundles = [
376 externals: ['react'],
377 },
378
379 + /******* React Stream *******/
380 + {
381 + bundleTypes: [NODE_DEV, NODE_PROD],
382 + moduleType: RECONCILER,
383 + entry: 'react-stream',
384 + global: 'ReactStream',
385 + externals: ['react'],
386 + },
387 +
388 /******* Reflection *******/
389 {
390 moduleType: RENDERER_UTILS,
scripts/rollup/forks.js
+60
@@ -272,6 +272,66 @@ const forks = Object.freeze({
272 );
273 },
274
275 + 'react-stream/src/ReactFizzHostConfig': (
276 + bundleType,
277 + entry,
278 + dependencies,
279 + moduleType
280 + ) => {
281 + if (dependencies.indexOf('react-stream') !== -1) {
282 + return null;
283 + }
284 + if (moduleType !== RENDERER && moduleType !== RECONCILER) {
285 + return null;
286 + }
287 + // eslint-disable-next-line no-for-of-loops/no-for-of-loops
288 + for (let rendererInfo of inlinedHostConfigs) {
289 + if (rendererInfo.entryPoints.indexOf(entry) !== -1) {
290 + if (!rendererInfo.isFizzSupported) {
291 + return null;
292 + }
293 + return `react-stream/src/forks/ReactFizzHostConfig.${
294 + rendererInfo.shortName
295 + }.js`;
296 + }
297 + }
298 + throw new Error(
299 + 'Expected ReactFizzHostConfig to always be replaced with a shim, but ' +
300 + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` +
301 + 'Did you mean to add it there to associate it with a specific renderer?'
302 + );
303 + },
304 +
305 + 'react-stream/src/ReactFizzFormatConfig': (
306 + bundleType,
307 + entry,
308 + dependencies,
309 + moduleType
310 + ) => {
311 + if (dependencies.indexOf('react-stream') !== -1) {
312 + return null;
313 + }
314 + if (moduleType !== RENDERER && moduleType !== RECONCILER) {
315 + return null;
316 + }
317 + // eslint-disable-next-line no-for-of-loops/no-for-of-loops
318 + for (let rendererInfo of inlinedHostConfigs) {
319 + if (rendererInfo.entryPoints.indexOf(entry) !== -1) {
320 + if (!rendererInfo.isFizzSupported) {
321 + return null;
322 + }
323 + return `react-stream/src/forks/ReactFizzFormatConfig.${
324 + rendererInfo.shortName
325 + }.js`;
326 + }
327 + }
328 + throw new Error(
329 + 'Expected ReactFizzFormatConfig to always be replaced with a shim, but ' +
330 + `found no mention of "${entry}" entry point in ./scripts/shared/inlinedHostConfigs.js. ` +
331 + 'Did you mean to add it there to associate it with a specific renderer?'
332 + );
333 + },
334 +
335 // We wrap top-level listeners into guards on www.
336 'react-dom/src/events/EventListener': (bundleType, entry) => {
337 switch (bundleType) {
scripts/rollup/results.json
+164 -80
@@ -46,29 +46,29 @@
46 "filename": "react-dom.development.js",
47 "bundleType": "UMD_DEV",
48 "packageName": "react-dom",
49 - "size": 725515,
50 - "gzip": 167737
49 + "size": 725813,
50 + "gzip": 167799
51 },
52 {
53 "filename": "react-dom.production.min.js",
54 "bundleType": "UMD_PROD",
55 "packageName": "react-dom",
56 - "size": 100307,
57 - "gzip": 32617
56 + "size": 99920,
57 + "gzip": 32521
58 },
59 {
60 "filename": "react-dom.development.js",
61 "bundleType": "NODE_DEV",
62 "packageName": "react-dom",
63 - "size": 720713,
64 - "gzip": 166331
63 + "size": 721011,
64 + "gzip": 166399
65 },
66 {
67 "filename": "react-dom.production.min.js",
68 "bundleType": "NODE_PROD",
69 "packageName": "react-dom",
70 - "size": 100301,
71 - "gzip": 32146
70 + "size": 99914,
71 + "gzip": 32052
72 },
73 {
74 "filename": "ReactDOM-dev.js",
@@ -165,8 +165,8 @@
165 "filename": "react-dom-server.browser.development.js",
166 "bundleType": "UMD_DEV",
167 "packageName": "react-dom",
168 - "size": 120524,
169 - "gzip": 32011
168 + "size": 122056,
169 + "gzip": 32469
170 },
171 {
172 "filename": "react-dom-server.browser.production.min.js",
@@ -179,8 +179,8 @@
179 "filename": "react-dom-server.browser.development.js",
180 "bundleType": "NODE_DEV",
181 "packageName": "react-dom",
182 - "size": 116562,
183 - "gzip": 31037
182 + "size": 118094,
183 + "gzip": 31495
184 },
185 {
186 "filename": "react-dom-server.browser.production.min.js",
@@ -207,8 +207,8 @@
207 "filename": "react-dom-server.node.development.js",
208 "bundleType": "NODE_DEV",
209 "packageName": "react-dom",
210 - "size": 118530,
211 - "gzip": 31584
210 + "size": 120062,
211 + "gzip": 32036
212 },
213 {
214 "filename": "react-dom-server.node.production.min.js",
@@ -221,29 +221,29 @@
221 "filename": "react-art.development.js",
222 "bundleType": "UMD_DEV",
223 "packageName": "react-art",
224 - "size": 507548,
225 - "gzip": 112066
224 + "size": 507846,
225 + "gzip": 112120
226 },
227 {
228 "filename": "react-art.production.min.js",
229 "bundleType": "UMD_PROD",
230 "packageName": "react-art",
231 - "size": 92284,
232 - "gzip": 28330
231 + "size": 91897,
232 + "gzip": 28219
233 },
234 {
235 "filename": "react-art.development.js",
236 "bundleType": "NODE_DEV",
237 "packageName": "react-art",
238 - "size": 437685,
239 - "gzip": 94610
238 + "size": 437983,
239 + "gzip": 94680
240 },
241 {
242 "filename": "react-art.production.min.js",
243 "bundleType": "NODE_PROD",
244 "packageName": "react-art",
245 - "size": 56431,
246 - "gzip": 17393
245 + "size": 56044,
246 + "gzip": 17298
247 },
248 {
249 "filename": "ReactART-dev.js",
@@ -291,29 +291,29 @@
291 "filename": "react-test-renderer.development.js",
292 "bundleType": "UMD_DEV",
293 "packageName": "react-test-renderer",
294 - "size": 450653,
295 - "gzip": 97378
294 + "size": 450951,
295 + "gzip": 97435
296 },
297 {
298 "filename": "react-test-renderer.production.min.js",
299 "bundleType": "UMD_PROD",
300 "packageName": "react-test-renderer",
301 - "size": 57674,
302 - "gzip": 17698
301 + "size": 57293,
302 + "gzip": 17617
303 },
304 {
305 "filename": "react-test-renderer.development.js",
306 "bundleType": "NODE_DEV",
307 "packageName": "react-test-renderer",
308 - "size": 445754,
309 - "gzip": 96206
308 + "size": 446052,
309 + "gzip": 96263
310 },
311 {
312 "filename": "react-test-renderer.production.min.js",
313 "bundleType": "NODE_PROD",
314 "packageName": "react-test-renderer",
315 - "size": 57342,
316 - "gzip": 17539
315 + "size": 56955,
316 + "gzip": 17453
317 },
318 {
319 "filename": "ReactTestRenderer-dev.js",
@@ -375,29 +375,29 @@
375 "filename": "react-reconciler.development.js",
376 "bundleType": "NODE_DEV",
377 "packageName": "react-reconciler",
378 - "size": 435479,
379 - "gzip": 93068
378 + "size": 435777,
379 + "gzip": 93120
380 },
381 {
382 "filename": "react-reconciler.production.min.js",
383 "bundleType": "NODE_PROD",
384 "packageName": "react-reconciler",
385 - "size": 57593,
386 - "gzip": 17242
385 + "size": 57202,
386 + "gzip": 17158
387 },
388 {
389 "filename": "react-reconciler-persistent.development.js",
390 "bundleType": "NODE_DEV",
391 "packageName": "react-reconciler",
392 - "size": 433889,
393 - "gzip": 92426
392 + "size": 434187,
393 + "gzip": 92481
394 },
395 {
396 "filename": "react-reconciler-persistent.production.min.js",
397 "bundleType": "NODE_PROD",
398 "packageName": "react-reconciler",
399 - "size": 57604,
400 - "gzip": 17248
399 + "size": 57213,
400 + "gzip": 17164
401 },
402 {
403 "filename": "react-reconciler-reflection.development.js",
@@ -515,15 +515,15 @@
515 "filename": "ReactDOM-dev.js",
516 "bundleType": "FB_WWW_DEV",
517 "packageName": "react-dom",
518 - "size": 742105,
519 - "gzip": 167549
518 + "size": 742241,
519 + "gzip": 167544
520 },
521 {
522 "filename": "ReactDOM-prod.js",
523 "bundleType": "FB_WWW_PROD",
524 "packageName": "react-dom",
525 - "size": 318358,
526 - "gzip": 58562
525 + "size": 317018,
526 + "gzip": 58396
527 },
528 {
529 "filename": "ReactTestUtils-dev.js",
@@ -550,8 +550,8 @@
550 "filename": "ReactDOMServer-dev.js",
551 "bundleType": "FB_WWW_DEV",
552 "packageName": "react-dom",
553 - "size": 117649,
554 - "gzip": 30639
553 + "size": 119227,
554 + "gzip": 31112
555 },
556 {
557 "filename": "ReactDOMServer-prod.js",
@@ -564,78 +564,78 @@
564 "filename": "ReactART-dev.js",
565 "bundleType": "FB_WWW_DEV",
566 "packageName": "react-art",
567 - "size": 445159,
568 - "gzip": 93560
567 + "size": 445295,
568 + "gzip": 93558
569 },
570 {
571 "filename": "ReactART-prod.js",
572 "bundleType": "FB_WWW_PROD",
573 "packageName": "react-art",
574 - "size": 189135,
575 - "gzip": 32266
574 + "size": 187912,
575 + "gzip": 32090
576 },
577 {
578 "filename": "ReactNativeRenderer-dev.js",
579 "bundleType": "RN_FB_DEV",
580 "packageName": "react-native-renderer",
581 - "size": 573357,
582 - "gzip": 124963
581 + "size": 573493,
582 + "gzip": 124971
583 },
584 {
585 "filename": "ReactNativeRenderer-prod.js",
586 "bundleType": "RN_FB_PROD",
587 "packageName": "react-native-renderer",
588 - "size": 245987,
589 - "gzip": 43227
588 + "size": 244566,
589 + "gzip": 43021
590 },
591 {
592 "filename": "ReactNativeRenderer-dev.js",
593 "bundleType": "RN_OSS_DEV",
594 "packageName": "react-native-renderer",
595 - "size": 573046,
596 - "gzip": 124866
595 + "size": 573182,
596 + "gzip": 124874
597 },
598 {
599 "filename": "ReactNativeRenderer-prod.js",
600 "bundleType": "RN_OSS_PROD",
601 "packageName": "react-native-renderer",
602 - "size": 231080,
603 - "gzip": 40077
602 + "size": 229659,
603 + "gzip": 39880
604 },
605 {
606 "filename": "ReactFabric-dev.js",
607 "bundleType": "RN_FB_DEV",
608 "packageName": "react-native-renderer",
609 - "size": 563440,
610 - "gzip": 122415
609 + "size": 563576,
610 + "gzip": 122418
611 },
612 {
613 "filename": "ReactFabric-prod.js",
614 "bundleType": "RN_FB_PROD",
615 "packageName": "react-native-renderer",
616 - "size": 225188,
617 - "gzip": 38730
616 + "size": 223730,
617 + "gzip": 38540
618 },
619 {
620 "filename": "ReactFabric-dev.js",
621 "bundleType": "RN_OSS_DEV",
622 "packageName": "react-native-renderer",
623 - "size": 563475,
624 - "gzip": 122429
623 + "size": 563611,
624 + "gzip": 122433
625 },
626 {
627 "filename": "ReactFabric-prod.js",
628 "bundleType": "RN_OSS_PROD",
629 "packageName": "react-native-renderer",
630 - "size": 225224,
631 - "gzip": 38745
630 + "size": 223766,
631 + "gzip": 38555
632 },
633 {
634 "filename": "ReactTestRenderer-dev.js",
635 "bundleType": "FB_WWW_DEV",
636 "packageName": "react-test-renderer",
637 - "size": 453421,
638 - "gzip": 95442
637 + "size": 453557,
638 + "gzip": 95443
639 },
640 {
641 "filename": "ReactShallowRenderer-dev.js",
@@ -718,22 +718,22 @@
718 "filename": "react-dom.profiling.min.js",
719 "bundleType": "NODE_PROFILING",
720 "packageName": "react-dom",
721 - "size": 103137,
722 - "gzip": 32687
721 + "size": 102985,
722 + "gzip": 32673
723 },
724 {
725 "filename": "ReactNativeRenderer-profiling.js",
726 "bundleType": "RN_OSS_PROFILING",
727 "packageName": "react-native-renderer",
728 - "size": 236392,
729 - "gzip": 41298
728 + "size": 235342,
729 + "gzip": 41248
730 },
731 {
732 "filename": "ReactFabric-profiling.js",
733 "bundleType": "RN_OSS_PROFILING",
734 "packageName": "react-native-renderer",
735 - "size": 229595,
736 - "gzip": 40005
735 + "size": 228530,
736 + "gzip": 39962
737 },
738 {
739 "filename": "Scheduler-dev.js",
@@ -767,22 +767,22 @@
767 "filename": "ReactDOM-profiling.js",
768 "bundleType": "FB_WWW_PROFILING",
769 "packageName": "react-dom",
770 - "size": 324711,
771 - "gzip": 59847
770 + "size": 323954,
771 + "gzip": 59824
772 },
773 {
774 "filename": "ReactNativeRenderer-profiling.js",
775 "bundleType": "RN_FB_PROFILING",
776 "packageName": "react-native-renderer",
777 - "size": 251555,
778 - "gzip": 44455
777 + "size": 250505,
778 + "gzip": 44397
779 },
780 {
781 "filename": "ReactFabric-profiling.js",
782 "bundleType": "RN_FB_PROFILING",
783 "packageName": "react-native-renderer",
784 - "size": 229554,
785 - "gzip": 39988
784 + "size": 228489,
785 + "gzip": 39945
786 },
787 {
788 "filename": "react.profiling.min.js",
@@ -795,8 +795,8 @@
795 "filename": "react-dom.profiling.min.js",
796 "bundleType": "UMD_PROFILING",
797 "packageName": "react-dom",
798 - "size": 103046,
799 - "gzip": 33256
798 + "size": 102894,
799 + "gzip": 33243
800 },
801 {
802 "filename": "scheduler-tracing.development.js",
@@ -937,6 +937,90 @@
937 "packageName": "eslint-plugin-react-hooks",
938 "size": 4943,
939 "gzip": 1815
940 + },
941 + {
942 + "filename": "ReactDOMFizzServer-dev.js",
943 + "bundleType": "FB_WWW_DEV",
944 + "packageName": "react-dom",
945 + "size": 3772,
946 + "gzip": 1432
947 + },
948 + {
949 + "filename": "ReactDOMFizzServer-prod.js",
950 + "bundleType": "FB_WWW_PROD",
951 + "packageName": "react-dom",
952 + "size": 2211,
953 + "gzip": 874
954 + },
955 + {
956 + "filename": "react-noop-renderer-server.development.js",
957 + "bundleType": "NODE_DEV",
958 + "packageName": "react-noop-renderer",
959 + "size": 1861,
960 + "gzip": 869
961 + },
962 + {
963 + "filename": "react-noop-renderer-server.production.min.js",
964 + "bundleType": "NODE_PROD",
965 + "packageName": "react-noop-renderer",
966 + "size": 804,
967 + "gzip": 482
968 + },
969 + {
970 + "filename": "react-stream.development.js",
971 + "bundleType": "NODE_DEV",
972 + "packageName": "react-stream",
973 + "size": 4633,
974 + "gzip": 1683
975 + },
976 + {
977 + "filename": "react-stream.production.min.js",
978 + "bundleType": "NODE_PROD",
979 + "packageName": "react-stream",
980 + "size": 1224,
981 + "gzip": 655
982 + },
983 + {
984 + "filename": "react-dom-unstable-fizz.browser.development.js",
985 + "bundleType": "UMD_DEV",
986 + "packageName": "react-dom",
987 + "size": 3704,
988 + "gzip": 1463
989 + },
990 + {
991 + "filename": "react-dom-unstable-fizz.browser.production.min.js",
992 + "bundleType": "UMD_PROD",
993 + "packageName": "react-dom",
994 + "size": 1227,
995 + "gzip": 697
996 + },
997 + {
998 + "filename": "react-dom-unstable-fizz.browser.development.js",
999 + "bundleType": "NODE_DEV",
1000 + "packageName": "react-dom",
1001 + "size": 3528,
1002 + "gzip": 1416
1003 + },
1004 + {
1005 + "filename": "react-dom-unstable-fizz.browser.production.min.js",
1006 + "bundleType": "NODE_PROD",
1007 + "packageName": "react-dom",
1008 + "size": 1063,
1009 + "gzip": 628
1010 + },
1011 + {
1012 + "filename": "react-dom-unstable-fizz.node.development.js",
1013 + "bundleType": "NODE_DEV",
1014 + "packageName": "react-dom",
1015 + "size": 3780,
1016 + "gzip": 1443
1017 + },
1018 + {
1019 + "filename": "react-dom-unstable-fizz.node.production.min.js",
1020 + "bundleType": "NODE_PROD",
1021 + "packageName": "react-dom",
1022 + "size": 1122,
1023 + "gzip": 659
1024 }
1025 ]
1026 }
\ No newline at end of file
scripts/rollup/validate/eslintrc.cjs.js
+2
@@ -18,6 +18,8 @@ module.exports = {
18 __REACT_DEVTOOLS_GLOBAL_HOOK__: true,
19 // CommonJS / Node
20 process: true,
21 + setImmediate: true,
22 + Buffer: true,
23 },
24 parserOptions: {
25 ecmaVersion: 5,
scripts/rollup/validate/eslintrc.fb.js
+3
@@ -18,6 +18,9 @@ module.exports = {
18 __REACT_DEVTOOLS_GLOBAL_HOOK__: true,
19 // FB
20 __DEV__: true,
21 + // Node.js Server Rendering
22 + setImmediate: true,
23 + Buffer: true,
24 },
25 parserOptions: {
26 ecmaVersion: 5,
scripts/shared/inlinedHostConfigs.js
+18 -2
@@ -9,8 +9,15 @@
9 module.exports = [
10 {
11 shortName: 'dom',
12 - entryPoints: ['react-dom'],
12 + entryPoints: ['react-dom', 'react-dom/unstable-fizz.node'],
13 isFlowTyped: true,
14 + isFizzSupported: true,
15 + },
16 + {
17 + shortName: 'dom-browser',
18 + entryPoints: ['react-dom/unstable-fizz.browser'],
19 + isFlowTyped: true,
20 + isFizzSupported: true,
21 },
22 {
23 shortName: 'fire',
@@ -21,25 +28,34 @@ module.exports = [
28 shortName: 'art',
29 entryPoints: ['react-art'],
30 isFlowTyped: false, // TODO: type it.
31 + isFizzSupported: false,
32 },
33 {
34 shortName: 'native',
35 entryPoints: ['react-native-renderer'],
36 isFlowTyped: true,
37 + isFizzSupported: false,
38 },
39 {
40 shortName: 'fabric',
41 entryPoints: ['react-native-renderer/fabric'],
42 isFlowTyped: true,
43 + isFizzSupported: false,
44 },
45 {
46 shortName: 'test',
47 entryPoints: ['react-test-renderer'],
48 isFlowTyped: true,
49 + isFizzSupported: false,
50 },
51 {
52 shortName: 'custom',
42 - entryPoints: ['react-reconciler', 'react-reconciler/persistent'],
53 + entryPoints: [
54 + 'react-reconciler',
55 + 'react-reconciler/persistent',
56 + 'react-stream',
57 + ],
58 isFlowTyped: true,
59 + isFizzSupported: true,
60 },
61 ];
yarn.lock
+12
@@ -94,6 +94,18 @@
94 lodash "^4.17.10"
95 to-fast-properties "^2.0.0"
96
97 +"@mattiasbuelens/web-streams-polyfill@0.1.0":
98 + version "0.1.0"
99 + resolved "https://registry.yarnpkg.com/@mattiasbuelens/web-streams-polyfill/-/web-streams-polyfill-0.1.0.tgz#c06ebfa7e00cc512a878c3aaae4cf113ac89ac24"
100 + integrity sha512-oMsvblvOezdM/j1ph0uU8s6Wm0EfCyMZtZcxQ232CqSpjm08lrKPizeMltN0eVv4dQf0DDFaxUFyiz8x51lgAA==
101 + dependencies:
102 + "@types/whatwg-streams" "^0.0.6"
103 +
104 +"@types/whatwg-streams@^0.0.6":
105 + version "0.0.6"
106 + resolved "https://registry.yarnpkg.com/@types/whatwg-streams/-/whatwg-streams-0.0.6.tgz#5062c67efb695c886fe3dbb9618df35aac418503"
107 + integrity sha512-O4Hat94N1RUCObqAbVUtd6EcucseqBcpfbFXzy12CYF6BQVHWR+ztDA3YPjewCmdKHYZ5VA7TZ5hq2bMyqxiBw==
108 +
109 abab@^1.0.4:
110 version "1.0.4"
111 resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"