Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fizz] New Server Rendering Infra #14144

Merged
merged 12 commits into from
Nov 30, 2018
Merged
40 changes: 40 additions & 0 deletions fixtures/fizz-ssr-browser/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html style="width: 100%; height: 100%; overflow: hidden">
<head>
<meta charset="utf-8">
<title>Fizz Example</title>
</head>
<body>
<h1>Fizz Example</h1>
<div id="container">
<p>
To install React, follow the instructions on
<a href="https://github.com/facebook/react/">GitHub</a>.
</p>
<p>
If you can see this, React is <strong>not</strong> working right.
If you checked out the source from GitHub make sure to run <code>npm run build</code>.
</p>
</div>
<script src="../../build/dist/react.development.js"></script>
<script src="../../build/dist/react-dom-unstable-fizz.browser.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<script type="text/babel">
let stream = ReactDOMFizzServer.renderToReadableStream(<body>Success</body>);
let response = new Response(stream, {
headers: {'Content-Type': 'text/html'},
});
display(response);

async function display(responseToDisplay) {
let blob = await responseToDisplay.blob();
let url = URL.createObjectURL(blob);
let iframe = document.createElement('iframe');
iframe.src = url;
let container = document.getElementById('container');
container.innerHTML = '';
container.appendChild(iframe);
}
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 7 additions & 0 deletions packages/react-dom/npm/unstable-fizz.browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-dom-unstable-fizz.browser.production.min.js');
} else {
module.exports = require('./cjs/react-dom-unstable-fizz.browser.development.js');
}
3 changes: 3 additions & 0 deletions packages/react-dom/npm/unstable-fizz.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = require('./unstable-fizz.node');
7 changes: 7 additions & 0 deletions packages/react-dom/npm/unstable-fizz.node.js
Original file line number Diff line number Diff line change
@@ -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');
}
6 changes: 5 additions & 1 deletion packages/react-dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@
"server.node.js",
"test-utils.js",
"unstable-fire.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": [
Expand Down
45 changes: 45 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
Original file line number Diff line number Diff line change
@@ -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(
<div>hello world</div>,
);
let result = await readResult(stream);
expect(result).toBe('<div>hello world</div>');
});
});
39 changes: 39 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* 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
* @jest-environment node
*/

'use strict';

let Stream;
let React;
let ReactDOMFizzServer;

describe('ReactDOMFizzServer', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOMFizzServer = require('react-dom/unstable-fizz');
Stream = require('stream');
});

function getTestWritable() {
let writable = new Stream.PassThrough();
writable.setEncoding('utf8');
writable.result = '';
writable.on('data', chunk => (writable.result += chunk));
return writable;
}

it('should call pipeToNodeWritable', () => {
let writable = getTestWritable();
ReactDOMFizzServer.pipeToNodeWritable(<div>hello world</div>, writable);
jest.runAllTimers();
expect(writable.result).toBe('<div>hello world</div>');
});
});
34 changes: 34 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerBrowser.js
Original file line number Diff line number Diff line change
@@ -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,
};
19 changes: 19 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerFormatConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* 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 {convertStringToBuffer} from 'react-stream/src/ReactFizzHostConfig';

export function formatChunk(type: string, props: Object): Uint8Array {
let str = '<' + type + '>';
if (typeof props.children === 'string') {
str += props.children;
}
str += '</' + type + '>';
return convertStringToBuffer(str);
}
30 changes: 30 additions & 0 deletions packages/react-dom/src/server/ReactDOMFizzServerNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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 {Writable} from 'stream';

import {createRequest, startWork, startFlowing} from 'react-stream/inline.dom';

function createDrainHandler(destination, request) {
return () => startFlowing(request, 0);
}

function pipeToNodeWritable(
children: ReactNodeList,
destination: Writable,
): void {
let request = createRequest(children, destination);
destination.on('drain', createDrainHandler(destination, request));
startWork(request);
}

export default {
pipeToNodeWritable,
};
16 changes: 16 additions & 0 deletions packages/react-dom/unstable-fizz.browser.js
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 12 additions & 0 deletions packages/react-dom/unstable-fizz.js
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
*/

'use strict';

module.exports = require('./unstable-fizz.node');
16 changes: 16 additions & 0 deletions packages/react-dom/unstable-fizz.node.js
Original file line number Diff line number Diff line change
@@ -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 ReactDOMFizzServerNode = require('./src/server/ReactDOMFizzServerNode');

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest
module.exports = ReactDOMFizzServerNode.default || ReactDOMFizzServerNode;
7 changes: 7 additions & 0 deletions packages/react-noop-renderer/npm/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-noop-renderer-server.production.min.js');
} else {
module.exports = require('./cjs/react-noop-renderer-server.development.js');
}
4 changes: 3 additions & 1 deletion packages/react-noop-renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"regenerator-runtime": "^0.11.0",
"react-reconciler": "*"
"react-reconciler": "*",
"react-stream": "*"
},
"peerDependencies": {
"react": "^16.0.0"
Expand All @@ -21,6 +22,7 @@
"build-info.json",
"index.js",
"persistent.js",
"server.js",
"cjs/"
]
}
16 changes: 16 additions & 0 deletions packages/react-noop-renderer/server.js
Original file line number Diff line number Diff line change
@@ -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 ReactNoopServer = require('./src/ReactNoopServer');

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactNoopServer.default || ReactNoopServer;
Loading