Skip to content

Commit e65b22f

Browse files
committed
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.
1 parent 81ce2c5 commit e65b22f

23 files changed

+286
-26
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@
8484
"targz": "^1.0.1",
8585
"through2": "^2.0.0",
8686
"tmp": "~0.0.28",
87-
"typescript": "~1.8.10"
87+
"typescript": "~1.8.10",
88+
"@mattiasbuelens/web-streams-polyfill": "0.1.0"
8889
},
8990
"devEngines": {
9091
"node": "8.x || 9.x || 10.x"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
if (process.env.NODE_ENV === 'production') {
4-
module.exports = require('./cjs/react-dom-unstable-fizz.production.min.js');
4+
module.exports = require('./cjs/react-dom-unstable-fizz.node.production.min.js');
55
} else {
6-
module.exports = require('./cjs/react-dom-unstable-fizz.development.js');
6+
module.exports = require('./cjs/react-dom-unstable-fizz.node.development.js');
77
}

packages/react-dom/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@
3131
"server.node.js",
3232
"test-utils.js",
3333
"unstable-fizz.js",
34+
"unstable-fizz.browser.js",
3435
"unstable-fizz.node.js",
3536
"unstable-native-dependencies.js",
3637
"cjs/",
3738
"umd/"
3839
],
3940
"browser": {
40-
"./server.js": "./server.browser.js"
41+
"./server.js": "./server.browser.js",
42+
"./unstable-fizz.js": "./unstable-fizz.browser.js"
4143
},
4244
"browserify": {
4345
"transform": [
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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/ReactDOMFizzServerNode.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ function createDrainHandler(destination, request) {
1616
return () => startFlowing(request, 0);
1717
}
1818

19-
function pipeToNodeWritable(children: ReactNodeList, destination: Writable) {
19+
function pipeToNodeWritable(
20+
children: ReactNodeList,
21+
destination: Writable,
22+
): void {
2023
let request = createRequest(children, destination);
2124
destination.on('drain', createDrainHandler(destination, request));
2225
startWork(request);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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-noop-renderer/src/ReactNoopServer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const ReactNoopServer = ReactFizzStreamer({
2727
destination.push(JSON.parse(Buffer.from((buffer: any)).toString('utf8')));
2828
},
2929
completeWriting(destination: Destination): void {},
30+
close(destination: Destination): void {},
3031
flushBuffered(destination: Destination): void {},
3132
convertStringToBuffer(content: string): Uint8Array {
3233
return Buffer.from(content, 'utf8');
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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';
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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';
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ export function completeWriting(destination: Destination) {
3939
destination.uncork();
4040
}
4141

42+
export function close(destination: Destination) {
43+
destination.end();
44+
}
45+
4246
export function convertStringToBuffer(content: string): Uint8Array {
4347
return Buffer.from(content, 'utf8');
4448
}

packages/react-stream/src/ReactFizzStreamer.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
writeChunk,
1717
completeWriting,
1818
flushBuffered,
19+
close,
1920
} from './ReactFizzHostConfig';
2021
import {formatChunk} from './ReactFizzFormatConfig';
2122
import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
@@ -36,7 +37,8 @@ export function createRequest(
3637

3738
function performWork(request: OpaqueRequest): void {
3839
let element = (request.children: any);
39-
if (element.$$typeof !== REACT_ELEMENT_TYPE) {
40+
request.children = null;
41+
if (element && element.$$typeof !== REACT_ELEMENT_TYPE) {
4042
return;
4143
}
4244
let type = element.type;
@@ -55,6 +57,7 @@ function performWork(request: OpaqueRequest): void {
5557
function flushCompletedChunks(request: OpaqueRequest) {
5658
let destination = request.destination;
5759
let chunks = request.completedChunks;
60+
request.completedChunks = [];
5861

5962
beginWriting(destination);
6063
try {
@@ -65,6 +68,7 @@ function flushCompletedChunks(request: OpaqueRequest) {
6568
} finally {
6669
completeWriting(destination);
6770
}
71+
close(destination);
6872
}
6973

7074
export function startWork(request: OpaqueRequest): void {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ export const beginWriting = $$$hostConfig.beginWriting;
3131
export const writeChunk = $$$hostConfig.writeChunk;
3232
export const completeWriting = $$$hostConfig.completeWriting;
3333
export const flushBuffered = $$$hostConfig.flushBuffered;
34+
export const close = $$$hostConfig.close;
3435
export const convertStringToBuffer = $$$hostConfig.convertStringToBuffer;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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';

scripts/rollup/bundles.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,17 @@ const bundles = [
140140
},
141141

142142
/******* React DOM Fizz Server *******/
143+
{
144+
bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD],
145+
moduleType: RENDERER,
146+
entry: 'react-dom/unstable-fizz.browser',
147+
global: 'ReactDOMFizzServer',
148+
externals: ['react'],
149+
},
143150
{
144151
bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD],
145152
moduleType: RENDERER,
146-
entry: 'react-dom/unstable-fizz',
153+
entry: 'react-dom/unstable-fizz.node',
147154
global: 'ReactDOMFizzServer',
148155
externals: ['react'],
149156
},

0 commit comments

Comments
 (0)